home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / DocShell / RlShell.cpp < prev    next >
Encoding:
Text File  |  1997-02-13  |  131.4 KB  |  4,651 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        RlShell.cpp
  3.  
  4.     Contains:    Shell implementation
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1993 - 1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <58>      1/8/97    DH        1401434: Check for low mem before
  13.                                     dispatching events
  14.         <57>    20.12.1996    NP        1614842: Can't save a copy over existing
  15.                                     doc.
  16.         <56>      12/19/96    TJ        Localization Fix
  17.         <55>     12/3/96    JP        1401371,1162540: Call SetProcessName &
  18.                                     SetProcessIcon
  19.         <54>      11/27/96    CSL        1385215: Support for container app windows.
  20.                                     1400043: more orphan mouse-up fixes
  21.         <53>      11/22/96    EL        1397453: preferences menu item number
  22.                                     should not be hard coded.
  23.         <52>      10/22/96    DH        1378925: Discard orphan mouse-ups. Fixes
  24.                                     problems with the Control Strip and Apple
  25.                                     Guide sending mouse-up events without a
  26.                                     corresponding mouse-down. This was messing
  27.                                     up a lot of parts.
  28.         <51>     10/7/96    RA        1343748: Store the preferred editor and its
  29.                                     user string as a pair
  30.         <50>     10/5/96    JP        1162540,1162541: Process icon calls
  31.         <49>     10/5/96    NP        1386083: Comments concerning changes to
  32.                                     DocUtils. Added back low mem check.
  33.         <48>     10/4/96    CSL        1334277: Now call ShowAboutBox() in
  34.                                     DialogsLib
  35.         <47>    02.10.1996    NP        1386083: Make sure shell can shut down if
  36.                                     InitSession fails.
  37.         <46>     10/1/96    EL        1388429: Move menu id constant to
  38.                                     CmdDefs.xh.
  39.         <45>    27.09.1996    NP        1385775: Incorrect dialog after OD
  40.                                     initialization fails. 1379135: Save dialog
  41.                                     left up after failure. 1377649: Save a copy
  42.                                     can leave corrupt doc. 1278776, 1370393: No
  43.                                     stationery for viewers.
  44.         <44>     9/27/96    EL        1353486: document may become write
  45.                                     protected after opening.
  46.         <43>     9/24/96    eeh        1315787: Allow non-OD files with
  47.                                     31-character names
  48.         <42>    20.09.1996    NP        1386083: Rewrite document opening code
  49.         <41>     9/19/96    DH        Task: low memory changes. Removed exit with
  50.                                     2 low-mem exceptions back to Shell.
  51.         <40>     9/13/96    EL        1366287: delete stationery if error occurs
  52.                                     during generation.
  53.         <39>     8/13/96    DM        1362809,1376080: reset fatal container
  54.                                     error flags to false and call handler with
  55.                                     false to disallow suppression
  56.         <38>     7/30/96    eeh        1372943: test for kTranslateItem and -108
  57.         <37>     7/28/96    DH        If there are any errors in OpenFile
  58.                                     attempting to open the draft, we will
  59.                                     immediately exit the process. Temporary
  60.                                     low-memory fix.
  61.         <36>     7/24/96    NP        1369891: Send quit event to ourselves in
  62.                                     response to the quit menu command.
  63.         <35>    19.07.1996    NP        1370120: don't call ExceptionAlert when
  64.                                     InitODSession fails. Just go away.
  65.         <34>     7/11/96    TJ        Fixed Removing of UnsavedNewDocument from
  66.                                     Stationary
  67.         <33>     7/11/96    TJ        Fixed Name of function to check for MacOS 8
  68.         <32>     6/27/96    TJ        1334727 Truning stationery into document
  69.                                     can cause it to disappeare! is now realy
  70.                                     fixed.
  71.         <31>     6/23/96    NP        1323565: Refuse to run under MacOS 8.
  72.         <30>     6/22/96    TJ        1334727 Truning stationery into document
  73.                                     can cause it to disappeare!
  74.         <29>     6/21/96    jpa        1358818: Use "File" menu title in CyberDog.
  75.                                     1358820: Open "New" doc in same process in
  76.                                     CD. 1341242: (CL) Shouldn't be able to
  77.                                     activate windows w/modal dialog up
  78.         <28>     6/20/96    JP        1339269: Made quit handle the saving
  79.                                     parameter too
  80.         <27>     6/19/96    jpa        1357406: Call MMOverridePlatform in
  81.                                     Initialize method.
  82.         <26>     6/18/96    NP        1330731: Default stationery checkbox to
  83.                                     setting of Document Info.
  84.         <25>     6/14/96    eeh        1322456: check all frags in container
  85.         <24>     6/12/96    eeh        1315197: call parts' adjustMenus when F-key
  86.                                     pressed
  87.         <23>      6/7/96    eeh        T10017: function ptrs must be extern C
  88.         <22>      6/7/96    eeh        T10017: return CFM errors
  89.         <21>      6/7/96    eeh        T10017: call Dialogs lib instead of
  90.                                     DraftsWindow
  91.         <20>      6/5/96    EL        1355529: Use InitKindsPopUp in InfoUtil so
  92.                                     it don't need to be duplicated.
  93.         <19>    .06.1996    NP        10002: Launch time fixes, system process.
  94.         <18>     5/31/96    jpa        T10012: CyberDog process model (changes to
  95.                                     OpenFile, etc.)
  96.         <17>     5/24/96    JA        1246074: Native exception compatibility.
  97.         <16>    .05.1996    NP        1352438: Factor IsOptionKeyDown and
  98.                                     IsAnyKeyDown
  99.         <15>      5/8/96    NP        1282265: saving as stationery looks like
  100.                                     document
  101.         <14>      5/1/96    JA        1213332: Force 68K struct alignment of
  102.                                     'cfrg'. Init MW profiler.
  103.         <13>    .04.1996    NP        1286751: Present alert when trying to use
  104.                                     Open… when no Finder is running.
  105.         <12>      4/4/96    NP        1338241: If shell is in infinite loop,
  106.                                     quit.
  107.         <11>      4/2/96    RA        1320667: Call
  108.                                     Activate/DeactivateFrontWindows around
  109.                                     ShowAboutScreen modal dialog call
  110.         <10>     3/29/96    DM        1334273: propagate fatal Bento errors and
  111.                                     show low mem alert and quit when
  112.                                     out-of-memory err occurs while trying to
  113.                                     show low memory alert (solving infinite
  114.                                     loop).
  115.          <9>     3/22/96    CC        1307182: UpdateMenus: Check for null edit
  116.                                     menu.
  117.          <8>    .03.1996    NP        1307182: Stuff for caching shell menu
  118.                                     items.
  119.          <7>     3/20/96    EL        1331460 Save a Copy does not include the
  120.                                     resources in parent document (e.g.
  121.                                     preferred memory size)
  122.          <6>     3/14/96    NP        1287354: Hide invisible files in the Open
  123.                                     Document dialog.
  124.          <5>    .03.1996    NP        1223399: Don't show error dialog while
  125.                                     suspending.
  126.          <4>    .03.1996    NP        1304875,1317218: Fix can't-cancel problem
  127.                                     on receipt of quit event.
  128.          <3>      3/1/96    JP        1314798: Made new documents run from temp
  129.                                     file
  130.          <2>      1/4/96    eeh        1302569: handle fat plugins
  131.          
  132.     In Progress:
  133.         
  134. */
  135. #define _USE_DIALOGS_LIB_
  136.  
  137. #ifndef _PLFMDEF_
  138. #include <PlfmDef.h>
  139. #endif
  140.  
  141. #ifndef _SHELLDEF_
  142. #include "ShellDef.h"
  143. #endif
  144.  
  145. #ifndef _SHLMAIN_
  146. #include "ShlMain.h"
  147. #endif
  148.  
  149. #ifndef _DOCUTILS_
  150. #include "DocUtils.h"
  151. #endif
  152.  
  153. #ifndef _UTILDEFS_
  154. #include "UtilDefs.h"
  155. #endif
  156.  
  157. #ifndef _RLSHELL_
  158. #include "RlShell.h"
  159. #endif
  160.  
  161. #ifndef _SHPLUGIN_
  162. #include "ShPlugIn.h"
  163. #endif
  164.  
  165. #ifndef _BENTODEF_
  166. #include "BentoDef.h"
  167. #endif
  168.  
  169. #ifndef _USERSRCM_
  170. #include <UseRsrcM.h>
  171. #endif
  172.  
  173. #ifndef _EXCEPT_
  174. #include <Except.h>
  175. #endif
  176.  
  177. #ifndef SOM_Module_OpenDoc_Commands_defined
  178. #include <CmdDefs.xh>
  179. #endif
  180.  
  181. #ifndef _ODUTILS_
  182. #include <ODUtils.h>
  183. #endif
  184.  
  185. #ifndef _BINDNGH_
  186. #include <BindngH.h>
  187. #endif
  188.  
  189. #ifndef _BNDNSUTL_
  190. #include <BndNSUtl.h>
  191. #endif
  192.  
  193. #ifndef _TEMPOBJ_
  194. #include "TempObj.h"
  195. #endif
  196.  
  197. #ifndef _TEMPITER_
  198. #include "TempIter.h"
  199. #endif
  200.  
  201. #ifndef _ODMEMORY_
  202. #include <ODMemory.h>
  203. #endif
  204.  
  205. #ifndef _BARRAY_
  206. #include <BArray.h>
  207. #endif
  208.  
  209. #ifndef SOM_ODDispatcher_xh
  210. #include <Disptch.xh>
  211. #endif
  212.  
  213. #ifndef SOM_ODWindowState_xh
  214. #include <WinStat.xh>
  215. #endif
  216.  
  217. #ifndef SOM_ODWindowIterator_xh
  218. #include <WinIter.xh>
  219. #endif
  220.  
  221. #ifndef SOM_ODWindow_xh
  222. #include <Window.xh>
  223. #endif
  224.  
  225. #ifndef SOM_ODMenuBar_xh
  226. #include <MenuBar.xh>
  227. #endif
  228.  
  229. #ifndef _ORDCOLL_
  230. #include "OrdColl.h"
  231. #endif
  232.  
  233. #ifndef SOM_ODFrame_xh
  234. #include <Frame.xh>
  235. #endif
  236.  
  237. #ifndef SOM_ODFrameFacetIterator_xh
  238. #include <FrFaItr.xh>
  239. #endif
  240.  
  241. #ifndef SOM_Module_Apple_defined
  242. #include <Part.xh>
  243. #endif
  244.  
  245. #ifndef SOM_ODArbitrator_xh
  246. #include <Arbitrat.xh>
  247. #endif
  248.  
  249. #ifndef SOM_Module_OpenDoc_Foci_defined
  250. #include "Foci.xh"
  251. #endif
  252.  
  253. #ifndef SOM_ODSession_xh
  254. #include <ODSessn.xh>
  255. #endif
  256.  
  257. #ifndef SOM_ODLinkManager_xh
  258. #include <LinkMgr.xh>
  259. #endif
  260.  
  261. #ifndef SOM_ODStorageSystem_xh
  262. #include <ODStor.xh>
  263. #endif
  264.  
  265. #ifndef SOM_ODStorageUnit_xh
  266. #include <StorageU.xh>
  267. #endif
  268.  
  269. #ifndef SOM_ODDocument_xh
  270. #include <Document.xh>
  271. #endif
  272.  
  273. #ifndef SOM_ODContainer_xh
  274. #include <ODCtr.xh>
  275. #endif
  276.  
  277. #ifndef SOM_ODClipboard_xh
  278. #include <Clipbd.xh>
  279. #endif
  280.  
  281. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  282. #include <StdTypes.xh>
  283. #endif
  284.  
  285. #ifndef SOM_Module_OpenDoc_StdProps_defined
  286. #include <StdProps.xh>
  287. #endif
  288.  
  289. #ifndef _ITEXT_
  290. #include <IText.h>
  291. #endif
  292.  
  293. #ifndef _ISOSTR_
  294. #include <ISOStr.h>
  295. #endif
  296.  
  297. #ifndef _PASCLSTR_
  298. #include <PasclStr.h>
  299. #endif
  300.  
  301. #ifndef _STORUTIL_
  302. #include <StorUtil.h>
  303. #endif
  304.  
  305. #ifndef SOM_ODUndo_xh
  306. #include <Undo.xh>
  307. #endif
  308.  
  309. #ifndef SOM_ODInfo_xh
  310. #include <Info.xh>
  311. #endif
  312.  
  313. #ifndef _USE_DIALOGS_LIB_
  314. #ifndef _DRAFTWN_
  315. #include "DraftWn.h"
  316. #endif
  317. #endif
  318.  
  319. #ifndef _ODPRCS_
  320. #include "ODPrcs.h"
  321. #endif
  322.  
  323. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  324. #include <StdDefs.xh>
  325. #endif
  326.  
  327. #ifndef _INFOUTIL_
  328. #include <InfoUtil.h>
  329. #endif
  330.  
  331. #ifndef SOM_Module_OpenDoc_StandardExtensions_defined
  332. #include <StdExts.xh>
  333. #endif
  334.  
  335. #ifndef _STDTYPIO_
  336. #include <StdTypIO.h>
  337. #endif
  338.  
  339. #ifndef _DLOGUTIL_
  340. #include <DlogUtil.h>
  341. #endif
  342.  
  343. #ifndef _MEMMGR_
  344. #include <MemMgr.h>
  345. #endif
  346.  
  347. #if ODDebug
  348. #ifndef _MEMDEBG_
  349. #include <MemDebg.h>
  350. #endif
  351. #endif
  352.  
  353. #ifndef __QUICKDRAW__
  354. #include <QuickDraw.h>
  355. #endif
  356.  
  357. #ifndef __STANDARDFILE__
  358. #include <StandardFile.h>
  359. #endif
  360.  
  361. #ifndef __FOLDERS__
  362. #include <Folders.h>
  363. #endif
  364.  
  365. #ifndef __FONTS__
  366. #include <Fonts.h>
  367. #endif
  368.  
  369. #ifndef __MENUS__
  370. #include <Menus.h>
  371. #endif
  372.  
  373. #ifndef __OSEVENTS__
  374. #include <OSEvents.h>
  375. #endif
  376.  
  377. #ifndef __DIALOGS__
  378. #include <Dialogs.h>
  379. #endif
  380.  
  381. #ifndef __PACKAGES__
  382. #include <Packages.h>
  383. #endif
  384.  
  385. #ifndef __TOOLUTILS__
  386. #include <ToolUtils.h>
  387. #endif
  388.  
  389. #ifndef __DESK__
  390. #include <Desk.h>
  391. #endif
  392.  
  393. #ifndef __RESOURCES__
  394. #include <Resources.h>
  395. #endif
  396.  
  397. #ifndef __LOWMEM__
  398. #include <LowMem.h>
  399. #endif
  400.  
  401. #ifndef __GESTALTEQU__
  402. #include <GestaltEqu.h>
  403. #endif
  404.  
  405. #ifndef __SCRIPT__
  406. #include <Script.h>
  407. #endif
  408.  
  409. #ifndef __FINDER__
  410. #include <Finder.h>
  411. #endif
  412.  
  413. #ifndef __FILES__
  414. #include <Files.h>
  415. #endif
  416.  
  417. #ifndef __ICONS__
  418. #include <Icons.h>
  419. #endif
  420.  
  421. #ifndef __ALIASES__
  422. #include <Aliases.h>
  423. #endif
  424.  
  425. #ifndef __TEXTSERVICES__
  426. #include <TextServices.h>
  427. #endif
  428.  
  429. #ifndef __LIMITS__
  430. #include <limits.h>
  431. #endif
  432.  
  433. #ifndef __STRING__
  434. #include <string.h>
  435. #endif
  436.  
  437. #ifndef SOM_ODPartWrapper_xh
  438. #include "PartWrap.xh"
  439. #endif
  440.  
  441. #ifndef __STDIO__
  442. #include <stdio.h>
  443. #endif
  444.  
  445. #ifndef __SEGLOAD__
  446. #include "SegLoad.h"
  447. #endif
  448.  
  449. #ifndef _ODDEBUG_
  450. #include "ODDebug.h"
  451. #endif
  452.  
  453. #ifndef _MEMMGR_
  454. #include "MemMgr.h"
  455. #endif
  456.  
  457. #ifndef _MEMDEBG_
  458. #include "MemDebg.h"
  459. #endif
  460.  
  461. #ifndef _STORUTIL_
  462. #include <StorUtil.h>
  463. #endif
  464.  
  465. #ifndef _NMSPCUTL_
  466. #include <NmSpcUtl.h>
  467. #endif
  468.  
  469. #ifndef SOM_ODValueNameSpace_xh
  470. #include "ValueNS.xh"
  471. #endif
  472.  
  473. #ifndef SOM_ODBinding_xh
  474. #include <ODBindng.xh>
  475. #endif
  476.  
  477. #ifndef SOM_ODTranslation_xh
  478. #include <Translt.xh>
  479. #endif
  480.  
  481. #ifndef SOM_ODTypeList_xh
  482. #include <TypeList.xh>
  483. #endif
  484.  
  485. #ifndef SOM_ODTypeListIterator_xh
  486. #include <TypLsItr.xh>
  487. #endif
  488.  
  489. #ifndef _SIHELPER_
  490. #include <SIHelper.h>
  491. #endif
  492.  
  493. #ifndef _EDITRSET_
  494. #include <EditrSet.h>
  495. #endif
  496.  
  497. #ifndef _TRANSUTL_
  498. #include <TransUtl.h>
  499. #endif
  500.  
  501. #ifndef _CRAWL_
  502. #include <Crawl.h>
  503. #endif
  504.  
  505. #ifndef _SEUTILS_
  506. #include "SEUtils.h"
  507. #endif
  508.  
  509. #ifndef __EDITIONS__
  510. #include <Editions.h>
  511. #endif
  512.  
  513. #ifndef __CODEFRAGMENTS__
  514. #include <CodeFragments.h>
  515. #endif
  516.  
  517. #ifndef _CONSTDEF_
  518. #include <ConstDef.h>
  519. #endif
  520.  
  521. #ifndef _SHELLMEM_
  522. #include <ShellMem.h>
  523. #endif
  524.  
  525. #ifndef _ERRUTILS_
  526. #include <ErrUtils.h>
  527. #endif
  528.  
  529. #ifndef _ODXDPFNS_
  530. #include <ODXDpFns.h>
  531. #endif
  532.  
  533. #ifndef _ODDOCREF_
  534. #include "ODDocRef.h"
  535. #endif
  536.  
  537. #ifndef _DOCUTILP_
  538. #include "DocUtilP.h"
  539. #endif
  540.  
  541. #ifndef _MISCUTIL_
  542. #include "MiscUtil.h"
  543. #endif
  544.  
  545. #ifndef _BINDINGUTILS_
  546. #include "BindingUtils.h"
  547. #endif
  548.  
  549. #ifndef _PROCESSHACK_
  550. #include "ProcessHack.h"
  551. #endif
  552.  
  553. #ifndef _ABOUTBOX_
  554. #include "AboutBox.h"
  555. #endif
  556.  
  557. #ifndef _FINDOPENDOCFOLDER_
  558. #include "FindOpenDocFolder.h"
  559. #endif
  560.  
  561. #ifdef __MWERKS__
  562. #if __option(profile)
  563. #include <profiler.h>
  564. #endif
  565. #endif
  566.  
  567. #pragma segment RealShell
  568.  
  569. #if ODDebug
  570. //==============================================================================
  571. // Debugging #Defines
  572. //==============================================================================
  573.  
  574. #endif
  575.  
  576. //==============================================================================
  577. // Constants
  578. //==============================================================================
  579.  
  580. const  ODOSType  kODDASMenuRsrc    = 0x44525652; // 'DRVR';
  581.  
  582. const ODSLong    kMaxTimeBetweenLocationChecks = 3 * 60L;    // Background file check delay
  583.  
  584. const short kMaxUniqueNameTries = 100;
  585.  
  586.  
  587. const ODSShort    kUseSpecificScript = 0x1c;
  588.  
  589. #define kMaxNumberSuffixLength 11
  590.  
  591. // For window resizing
  592. #define kMinWindowWidth  192
  593. #define kMinWindowHeight 64
  594. #define kMaxWindowWidth  16384
  595. #define kMaxWindowHeight 16384
  596.  
  597. // from DrawDef.h
  598. #define kODKindTestDraw "Apple:Kind:TestDraw"
  599.  
  600. // Local error codes:
  601.  
  602. #define        kODErrClosingNonODWindow    5001
  603.  
  604.  
  605. #define ODDebugMenu ODDebug        /* Use Debug menu if debug build */
  606.  
  607.  
  608. #if ODDebugMenu
  609. const ODMenuID kDebugMenuID = 100;
  610. // Command IDs for the debugging menu:
  611. enum {
  612.     kODCommandDBHeapInfo = 980,
  613.     kODCommandDBDumpObjects,
  614.     kODCommandDBDumpBlocks,
  615.     kODCommandDBMemValidation,
  616.     kODCommandDBHeapChecking,
  617.     kODCommandDBLeakChecking,
  618.     kODCommandDBDumpBlocksOnClose,
  619.     kODCommandDBTrackStackCrawls,
  620.     kODCommandDBLogStdout,
  621.     kODCommandDBLogDebugWindow,
  622.     kODCommandDBLogDebugStr,
  623.     kODCommandDBSOMTrace,
  624.     kODCommandDBBreakOnThrow,
  625.     kODCommandDBEatMemory,
  626.     kODCommandDBPurge
  627. };
  628.  
  629. const short kODHeapInfoAlert = 980;
  630. #endif
  631.  
  632. const StringPtr kODEmptyPString = "\p";
  633.  
  634. //==============================================================================
  635. // Local Macros
  636. //==============================================================================
  637.  
  638. #if ODDebug
  639. #define SHLDebugStr(x)        DebugStr(x)
  640. #else
  641. #define SHLDebugStr(x)
  642. #endif
  643.  
  644. #define BITTEST( codes, thisCode )                                            \
  645.         (((codes) & (thisCode)) != 0L)
  646.  
  647. //#define SHLHeapDebug
  648. //#define SHLTestSessionOverhead
  649. //#define SHLTestErrorDialogUsage
  650.  
  651. //==============================================================================
  652. // Static variables
  653. //==============================================================================
  654.  
  655. #if ODDebug
  656. static ODBoolean gMemValidation = kODFalse;
  657. static ODBoolean gHeapChecking    = kODFalse;
  658. static ODBoolean gLeakChecking  = kODFalse;
  659. static ODBoolean gDumpBlocksOnClose      = kODFalse;
  660. static ODBoolean gTrackStackCrawls  = kODFalse;
  661. #endif
  662.  
  663. #ifndef __MWERKS__
  664. QDGlobals qd;
  665. #endif            
  666. // Need to declare 'qd' ourselves because even though 'qd' is already 
  667. // in Startup.c in the Metrowerks libraries, it is NOT necessarily in the
  668. // libraries for other compilers, e.g the compilers for CFM68K. -TÇ
  669.  
  670. //==============================================================================
  671. // Local Classes
  672. //==============================================================================
  673.  
  674. struct ErrRecord
  675. {
  676.     ODError lowErr, highErr;
  677.     ODULong index;
  678. };
  679.  
  680. typedef ErrRecord* ErrRecordPointer;
  681. typedef ErrRecordPointer* ErrRecordHandle;
  682.  
  683. //==============================================================================
  684. // Function Prototype
  685. //==============================================================================
  686.  
  687. void    CreateTempName(short seed, Str255 name, ODBoolean isFile);
  688.     // $opt: CreateTempName is duplicated in ODPrcs.cpp
  689.     
  690. void    GetTempFolder(ODSShort* VRef,ODSLong* DirID);
  691. void    CreateNewFile(PlatformFile* newFile, ODBoolean forceNewName); // newFile is in/out
  692.  
  693. pascal void DrawSmallIcon(DialogPtr theDialog, short theItem);
  694. pascal short SaveCopyDlgHook(short item, DialogPtr theDialog, void *yourDataPtr);
  695.  
  696. static ODIconFamily
  697. GetRootPartIconFamily( Environment*    ev, ODSession* session );
  698.  
  699. #if ODDebug
  700. static ODBoolean isHeapKeyDown();
  701.  
  702. static ODBoolean isFilterKeyDown();
  703.  
  704. static void HeapInfo();
  705.  
  706. #endif
  707.  
  708. ODStatic ODBoolean FindShellPlugInsFolder(short *vol, long *dir );
  709. ODStatic void FindStationeryFolder(short *vol, long *dir );
  710.                              
  711. ODStatic void    CreateNewUntitledFile(PlatformFile* newFile, 
  712.                         char* fileNameSeed = kODNULL);
  713. // Note: fileNameSeed is ignored if newFile->IsStationery()
  714.  
  715. static ODIText* CreateDefaultIText(StringPtr text);
  716. static OSErr SendFinderODOCEvent( const FSSpec *fileToOpen );
  717. ODStatic OSErr GetCfrgInfo( ODFileSpec* fileSpec, long* offset, long* length );
  718. ODStatic void    CopyResources(PlatformFile* srcFile, PlatformFile* dstFile);
  719.             
  720.  
  721. extern ODBoolean gODBentoFatalErrorHasOccurred; // SessHdr.cpp
  722. extern ODBoolean gODDelayBentoFatalError; // SessHdr.cpp
  723. extern ODBoolean gODSuppressBentoFatalError; // SessHdr.cpp
  724. extern void ODBentoFatalError(ODBoolean allowSuppress); // SessHdr.cpp
  725.                              
  726. #if ODDebug
  727. static void DumpHeapObjects( ODBoolean objectsOnly );
  728. #endif
  729.                              
  730. static void FinderNotRunning();
  731.  
  732. //==============================================================================
  733. // ShellMain Function
  734. //==============================================================================
  735.  
  736. #pragma lib_export on            // only ShellMain needs to be exported
  737.  
  738. #ifdef __cplusplus
  739. extern "C" {
  740. #endif
  741.  
  742. int ShellMain()
  743. {BreakOnThrow(kODTrue);
  744.     MaxApplZone();
  745.     MoreMasters();
  746.     MoreMasters();
  747.     MoreMasters();
  748.     MoreMasters();        // $Opt: May need more of these. Poke about at runtime to see.
  749.  
  750.     InitGraf(&qd.thePort);
  751.  
  752.     // Must init this here as well because we might need to use it before
  753.     //    OpenDoc is initialized. Copied from InitSession. Must be done after
  754.     //    InitGraf
  755.     *(QDGlobals**)&gODQD
  756.         = (QDGlobals*)( *(char**)LMGetCurrentA5()
  757.                                         - sizeof(QDGlobals) + sizeof(GrafPtr));
  758.  
  759.     InitFonts();
  760.     FlushEvents(everyEvent, 0);
  761.     InitWindows();
  762.     InitMenus();
  763.     TEInit();
  764.     InitDialogs(kODNULL);
  765.     WatchCursor();
  766.  
  767.     // Intialize Metrowerks profiler if this is a profiling build:
  768. #ifdef __MWERKS__
  769. #if __option(profile)
  770.     ProfilerInit(collectDetailed,bestTimeBase,3000,100);
  771.     ProfilerSetStatus(false);
  772. #endif
  773. #endif
  774.  
  775. /* Note below that we continue even if the Edition Manager or TSM are not around. 
  776.    There is no express reason that either one of these need to be around for OpenDoc
  777.    in general to function.  Lack of Edition Manager just means you can't do linking.
  778.  */
  779.  
  780.     if (InitEditionPack() != noErr)
  781.         SHLDebugStr("\pInitEditionPack failed");
  782.  
  783.     long gestaltResponse;
  784.     ODBoolean hasTSM = (Gestalt(gestaltTSMgrVersion, &gestaltResponse) == noErr) &&
  785.          (gestaltResponse >= 1);
  786.     if (hasTSM)
  787.     {
  788.         if (InitTSMAwareApplication() == noErr)
  789.         {
  790.             const TSMDocumentID    kAnyDoc = kODNULL;
  791.         
  792.             if (UseInputWindow(kAnyDoc, kODTrue) != noErr)
  793.                 SHLDebugStr("\pUseInputWindow failed.");
  794.         }
  795.         else
  796.         {
  797.             SHLDebugStr("\pInitTSMAwareApplication failed.");
  798.         }
  799.     }
  800.     else
  801.     {
  802.         SHLDebugStr("\pTSM unavailable.");
  803.     }
  804.     
  805.     TRY
  806.         ODInitExceptions();        // Sets up SOMError and SOMPrintf
  807.     
  808.     // CHECK FOR RUNNING UNDER MacOS8
  809.     {
  810.         CUsingLibraryResources    r;
  811.  
  812.         if (RunningUnderMacOS8())
  813.             return 1;
  814.     }
  815.  
  816.     #if ODDebug
  817.         MMBeginMemValidation();
  818.         gMemValidation = kODTrue;
  819.     #endif
  820.     
  821.     #if VALIDATE_EVERYTHING
  822.         // MMBeginMemValidation(); Should be taken care of by above.
  823.         MMBeginHeapChecking( );
  824.     #endif
  825.     
  826.         if (IsOptionKeyDown())
  827.             SHLDebugStr("\pAbout to create and enter the Shell.  You may proceed.");
  828.         
  829.     #if ODDebug
  830.         if (isHeapKeyDown())
  831.         {
  832.             SHLDebugStr("\pAbout to track heap block stack crawls. Type g to proceed.");
  833.             gDumpBlocksOnClose = kODTrue;
  834.             gTrackStackCrawls = kODTrue;
  835.         }
  836.     #endif
  837.         
  838.         RealShell*    le = new RealShell;
  839.         le->go();
  840.         delete le;
  841.         
  842.     #if VALIDATE_EVERYTHING
  843.         MMEndHeapChecking( );
  844.         MMEndMemValidation();
  845.     #endif
  846.     
  847.         if (hasTSM)
  848.             CloseTSMAwareApplication();
  849.     CATCH_ALL
  850.         /* Not much we can do here folks.
  851.            Either ODInitExceptions failed, or creating a RealShell object failed.
  852.            If the latter, then we don't have enough memory to put up a dialog.
  853.            If the former, then something is really wrong the runtime.
  854.          */
  855.         SHLDebugStr("\pException reached ShellMain. Possibly ODInitExceptions failed");
  856.     ENDTRY
  857.  
  858.     return 0;
  859. }
  860.  
  861. #ifdef __cplusplus
  862. }
  863. #endif
  864.  
  865. #pragma lib_export off
  866.  
  867. //==============================================================================
  868. // Static Functions
  869. //==============================================================================
  870.  
  871. #if ODDebug
  872. static ODBoolean isHeapKeyDown() // use 'h' to mean "heap"
  873. {
  874.     const ODUShort heapKey = 4;    // the 'h' key
  875.     return IsThisKeyDown(heapKey);
  876. }
  877. static ODBoolean isFilterKeyDown() // use 'f' to mean "filter"
  878. {
  879.     const ODUShort filterKey = 3;    // the 'f' key
  880.     return IsThisKeyDown(filterKey);
  881. }
  882. #endif
  883.  
  884. #if ODDebug
  885.  
  886. static void
  887. ParamTextHeapInfo( )
  888. {
  889.     const char *name;
  890.     size_t allocated, free,blocks,objects,contig;
  891.     
  892.     MMGetHeapInfo(kDefaultHeapID,
  893.                   &name, &allocated, &free, &blocks, &objects);
  894.     char nameStr[256], infoStr[256], appInfoStr[256];
  895.     strcpy((char*)nameStr, name);
  896.     sprintf(infoStr,"%lu\r%lu (%.1f%%)\r%lu (%lu objs)",
  897.             allocated, free,
  898.             100.0*free/(float)(allocated+free),
  899.             blocks,objects);
  900.  
  901.     MMSystemFreeSpace(kMMAppMemory, &free,&contig);
  902.     allocated = (ApplicationZone()->bkLim-(Ptr)&ApplicationZone()->heapData) - free;
  903.     sprintf(appInfoStr,"%lu\r%lu (%.1f%%)\r%lu",
  904.             allocated, free,
  905.             100.0*free/(float)(allocated+free),
  906.             contig);
  907.  
  908.     ParamText(CToPascalString(nameStr),CToPascalString(infoStr),
  909.               "\pMacOS Application Heap",CToPascalString(appInfoStr));
  910. }
  911.  
  912. static void HeapInfo()
  913. {
  914.     ParamTextHeapInfo();
  915.     ODSLong        savedRefNum;
  916.     BeginUsingLibraryResources(savedRefNum);
  917.     NoteAlert(kODHeapInfoAlert, NULL);
  918.     EndUsingLibraryResources(savedRefNum);
  919. }
  920.  
  921. #endif
  922.  
  923.  
  924. //==============================================================================
  925. // RealShell
  926. //==============================================================================
  927.  
  928.  
  929. //-------------------------------------------------------------------------------------
  930. // Initialization
  931. //-------------------------------------------------------------------------------------
  932.  
  933. RealShell::RealShell()
  934. {
  935.     fEV         = kODNULL;
  936.     fSession                 = kODNULL;
  937.     fDispatcher             = kODNULL;
  938.     fWindowState            = kODNULL;
  939.     fArbitrator                = kODNULL;
  940.     fSIHelper                = kODNULL;
  941.  
  942.     fModalFocusToken        = kODNullTypeToken;
  943.     fAlreadyInCoercion        = kODFalse;
  944.     fErrorFromOpenEvents    = noErr;
  945.     fUniqueNameSeed            = 1;
  946.     fShellHasMenuFocus        = kODFalse;
  947.     fLastNewDocPSN.lowLongOfPSN = kNoProcess;
  948.     fMouseButtonIsDown        = kODFalse;
  949.  
  950.     fSaveCopyData            = kODNULL;
  951.     fSaveDiffVolDialog        = kODNULL;
  952.     
  953.     fLowTempMemNotified = kODFalse;
  954.     fLowAppMemNotified = kODFalse;
  955.     fOutOfTempMemNotified = kODFalse;
  956.     
  957.     fFailedPlugInName[0]    = 0;
  958. }
  959.  
  960.  
  961. RealShell::~RealShell()
  962. {
  963.     
  964.     ODDeleteObject(fSIHelper);
  965.     
  966.     this->ExportClipboard(kODFalse);
  967. #ifdef SHLHeapDebug
  968.     SHLDebugStr("\pPostCloseDoc/PreSessionDelete HeapInfo…");
  969.     HeapInfo();
  970. #endif
  971.     if (fSession)
  972.         delete fSession;
  973. #ifdef SHLHeapDebug
  974.     SHLDebugStr("\pPostSessionDelete HeapInfo…");
  975.     HeapInfo();
  976. #endif
  977.  
  978. #if ODDebug
  979.     if( gDumpBlocksOnClose ) {
  980.         somPrintf("SOM objects and tracked blocks in heap contents after closing the session:\n");
  981.         DumpHeapObjects(/*objectsOnly*/ kODFalse);
  982.     }
  983. #endif
  984.     WASSERT(fSaveDiffVolDialog==kODNULL);
  985. }
  986.  
  987.  
  988.  
  989. void RealShell::Initialize()
  990. {
  991.     // Force NewPtr to allocate in our heap in temp mem. This fixes the problem
  992.     // of CFM global data choking the app heap!
  993.     MMOverridePlatform(kODTrue,kODFalse);
  994.     
  995.     fEV = somGetGlobalEnvironment();
  996.         
  997.     fSession = new ODSession;
  998.     THROW_IF_NULL(fSession); // som objects don't autothrow if unable to allocate.
  999.     // Shouldn't really set the instance var until session is fully inited,
  1000.     //    but I think that there is a lot of code that depends on having a
  1001.     //    valid pointer to a session. Arg.
  1002.     fSession->InitSession(fEV);
  1003.     // Note: we need fDispatcher & fWindowState BEFORE ShellPlugIns are installed.
  1004.     fDispatcher = fSession->GetDispatcher(fEV);
  1005.     fWindowState = fSession->GetWindowState(fEV);
  1006.     // Tell the window state to use its default window module
  1007.     fWindowState->SetWindowModule( fEV, kODNULL );
  1008.     
  1009.     fArbitrator = fSession->GetArbitrator( fEV );
  1010.  
  1011.     fModalFocusToken = fSession->Tokenize( fEV, kODModalFocus );
  1012.         
  1013.     // Is the app curently the active process?
  1014.     ProcessSerialNumber me = {0,kCurrentProcess};
  1015.     ProcessSerialNumber cur;
  1016.     GetFrontProcess(&cur);
  1017.     SameProcess(&me,&cur,&fProcessIsActive);
  1018.     
  1019.     // Is this an APPL process or a normal OD doc process?
  1020.     ProcessInfoRec info;
  1021.     this->GetCurrentProcessInfo(&info);
  1022.     fAPPLProcess = (info.processType=='APPL');
  1023.  
  1024.     this->InstallMenuBar();
  1025.     this->InitAE();
  1026.     this->InitMemory();
  1027. }
  1028.  
  1029. void RealShell::InstallMenuBar()
  1030. {
  1031.     ODSLong        savedRefNum;
  1032.     BeginUsingLibraryResources(savedRefNum);
  1033.  
  1034.     ODPlatformMenuBar    menuBar;
  1035.     menuBar = GetNewMBar(kODAppleMenuID);
  1036.     
  1037.     if( !menuBar ) THROW(resNotFound);
  1038.     SetMenuBar(menuBar);
  1039.  
  1040.     MenuHandle appleMenu = GetMenuHandle(kODAppleMenuID);
  1041.     DetachResource((Handle)appleMenu);
  1042.     
  1043. #if ODDebugMenu
  1044.     // Add "ODDebug" menu item, with submenu, below "About..." command:
  1045.     InsertMenuItem(appleMenu,"\pODDebug",1);
  1046.     SetItemCmd(appleMenu,2,0x1B);
  1047.     SetItemMark(appleMenu,2, kDebugMenuID);
  1048.     
  1049.     MenuHandle dbMenu = NewMenu(kDebugMenuID,"\pODDebug");
  1050.     THROW_IF_NULL(dbMenu);
  1051.     AppendMenu(dbMenu,    "\pHeap Info;"
  1052.                         "Memory Validation;"
  1053.                         "Heap Checking;"
  1054.                         "Leak Checking;"
  1055.                         "Dump Blocks On Close;"
  1056.                         "Track Block Stack Crawls;"
  1057.                         "Eat Memory;"
  1058.                         "Purge;"
  1059.                         "(-;"
  1060.                         "Log To stdout File;"
  1061.                         "Log To DebugWindow;"
  1062.                         "Generate DebugStrs;"
  1063.                         "Dump ODObjects;"
  1064.                         "Dump Tracked Blocks;"
  1065.                         "(-;"
  1066.                         "Break On THROW;"
  1067.                         "SOM Trace" );
  1068.     InsertMenu(dbMenu,hierMenu);
  1069.  
  1070.     const int kNumDebugMenuItems = 17;
  1071.  
  1072.     static const ODCommandID kDBCommands[kNumDebugMenuItems] = {kODCommandDBHeapInfo,
  1073.                                                 kODCommandDBMemValidation,
  1074.                                                 kODCommandDBHeapChecking,
  1075.                                                 kODCommandDBLeakChecking,
  1076.                                                 kODCommandDBDumpBlocksOnClose,
  1077.                                                 kODCommandDBTrackStackCrawls,
  1078.                                                 kODCommandDBEatMemory,
  1079.                                                 kODCommandDBPurge,
  1080.     /* Used below... */                            0,
  1081.                                                 kODCommandDBLogStdout,
  1082.                                                 kODCommandDBLogDebugWindow,
  1083.                                                 kODCommandDBLogDebugStr,
  1084.                                                 kODCommandDBDumpObjects,
  1085.                                                 kODCommandDBDumpBlocks,
  1086.                                                 0,
  1087.                                                 kODCommandDBBreakOnThrow,
  1088.                                                 kODCommandDBSOMTrace};
  1089.  
  1090.     DisposeHandle((Handle)menuBar);                // Update menuBar variable with new menu
  1091.     menuBar = GetMenuBar();
  1092. #endif
  1093.     
  1094.     // create a new ODMenuBar object
  1095.     TempODMenuBar baseMenuBar = fWindowState->CreateMenuBar(fEV, menuBar);
  1096.     
  1097.     // add DA names to Apple menu
  1098.     AppendResMenu(appleMenu, kODDASMenuRsrc);
  1099.  
  1100. #ifdef SUPPORT_QUIT
  1101.     // Load Document menu, or File menu if running in an 'APPL' process: [MenuIDs are identical!]
  1102.     MenuHandle documentMenu = GetMenu( fAPPLProcess ?kODFileMenuID :kODDocumentMenuID);
  1103. #else
  1104.     MenuHandle documentMenu = GetMenu(kODDocumentMenuID);
  1105. #endif
  1106.  
  1107.     DetachResource((Handle)documentMenu);
  1108.  
  1109.     baseMenuBar->AddMenuLast(fEV, kODDocumentMenuID, documentMenu, kODNULL);
  1110.  
  1111.     MenuHandle editMenu = GetMenu(kODEditMenuID);
  1112.     DetachResource((Handle)editMenu);
  1113.     baseMenuBar->AddMenuLast(fEV, kODEditMenuID, editMenu, kODNULL);
  1114.  
  1115. //    Save off the default undo and redo menu items so that we can use them when
  1116. //    there's nothing on the undo or redo stack.
  1117.  
  1118.     this->SaveMenuItem(appleMenu, kSHLMenuAbout, &fDefaultAboutMenuItem);
  1119.     this->SaveMenuItem(editMenu, kSHLMenuUndo, &fDefaultUndoMenuItem);
  1120.     this->SaveMenuItem(editMenu, kSHLMenuRedo, &fDefaultRedoMenuItem);
  1121.     this->SaveMenuItem(editMenu, kSHLMenuPreferences, &fDefaultPrefsMenuItem);
  1122.  
  1123.      EndUsingLibraryResources(savedRefNum);
  1124.  
  1125.     baseMenuBar->RegisterCommand(fEV, kODCommandAppleMenu, kODAppleMenuID, 0);
  1126.     baseMenuBar->RegisterCommand(fEV, kODCommandAbout, kODAppleMenuID, kSHLMenuAbout);
  1127.     
  1128.     baseMenuBar->RegisterCommand(fEV, kODCommandDocumentMenu, kODDocumentMenuID, 0);
  1129.     baseMenuBar->RegisterCommand(fEV, kODCommandNew, kODDocumentMenuID, kSHLMenuNew);
  1130.     baseMenuBar->RegisterCommand(fEV, kODCommandOpen, kODDocumentMenuID, kSHLMenuOpen);
  1131.     baseMenuBar->RegisterCommand(fEV, kODCommandOpenDocument, kODDocumentMenuID, kSHLMenuOpenDocument);
  1132.     baseMenuBar->RegisterCommand(fEV, kODCommandInsert, kODDocumentMenuID, kSHLMenuInsert);
  1133.     baseMenuBar->RegisterCommand(fEV, kODCommandClose, kODDocumentMenuID, kSHLMenuClose);
  1134.     baseMenuBar->RegisterCommand(fEV, kODCommandDeleteDocument, kODDocumentMenuID, kSHLMenuDeleteDocument);
  1135.     
  1136.     baseMenuBar->RegisterCommand(fEV, kODCommandSave, kODDocumentMenuID, kSHLMenuSave);
  1137.     baseMenuBar->RegisterCommand(fEV, kODCommandSaveACopy, kODDocumentMenuID, kSHLMenuSaveACopy);
  1138.     baseMenuBar->RegisterCommand(fEV, kODCommandRevert, kODDocumentMenuID, kSHLMenuRevert);
  1139.     baseMenuBar->RegisterCommand(fEV, kODCommandDraft, kODDocumentMenuID, kSHLMenuDraft);
  1140.     baseMenuBar->RegisterCommand(fEV, kODCommandDocumentInfo, kODDocumentMenuID, kSHLMenuDocumentInfo);
  1141.     
  1142.     baseMenuBar->RegisterCommand(fEV, kODCommandPageSetup, kODDocumentMenuID,
  1143.             kSHLMenuPageSetup );
  1144.     baseMenuBar->RegisterCommand(fEV, kODCommandPrint, kODDocumentMenuID,
  1145.             kSHLMenuPrint );
  1146.     
  1147. #ifdef SUPPORT_QUIT
  1148.     // If this is an APPL process like CyberDog, register "Quit" cmd
  1149.     if( fAPPLProcess )
  1150.         baseMenuBar->RegisterCommand(fEV, kODCommandQuit, kODDocumentMenuID, kSHLMenuQuit);
  1151. #endif
  1152.  
  1153.     baseMenuBar->RegisterCommand(fEV, kODCommandEditMenu, kODEditMenuID, 0);
  1154.     baseMenuBar->RegisterCommand(fEV, kODCommandUndo, kODEditMenuID, kSHLMenuUndo);
  1155.     baseMenuBar->RegisterCommand(fEV, kODCommandRedo, kODEditMenuID, kSHLMenuRedo);
  1156.     baseMenuBar->RegisterCommand(fEV, kODCommandCut, kODEditMenuID, kSHLMenuCut);
  1157.     baseMenuBar->RegisterCommand(fEV, kODCommandCopy, kODEditMenuID, kSHLMenuCopy);
  1158.     baseMenuBar->RegisterCommand(fEV, kODCommandPaste, kODEditMenuID, kSHLMenuPaste);
  1159.     baseMenuBar->RegisterCommand(fEV, kODCommandPasteAs, kODEditMenuID, kSHLMenuPasteAs);
  1160.     baseMenuBar->RegisterCommand(fEV, kODCommandClear, kODEditMenuID, kSHLMenuClear);
  1161.     baseMenuBar->RegisterCommand(fEV, kODCommandSelectAll, kODEditMenuID, kSHLMenuSelectAll);
  1162.     baseMenuBar->RegisterCommand(fEV, kODCommandGetPartInfo, kODEditMenuID, kSHLMenuGetPartInfo);
  1163.     baseMenuBar->RegisterCommand(fEV, kODCommandPreferences, kODEditMenuID, kSHLMenuPreferences);
  1164.     baseMenuBar->RegisterCommand(fEV, kODCommandViewAsWin, kODEditMenuID, kSHLMenuViewAsWin);
  1165.     
  1166. #if ODDebugMenu
  1167.     for( short i=0; i<kNumDebugMenuItems; i++ )
  1168.         if( kDBCommands[i] )
  1169.             baseMenuBar->RegisterCommand(fEV, kDBCommands[i], kDebugMenuID, i+1);
  1170. #endif
  1171.  
  1172.     fWindowState->SetBaseMenuBar(fEV,baseMenuBar);
  1173.     baseMenuBar->Display(fEV);
  1174. }
  1175.  
  1176. //------------------------------------------------------------------------------
  1177. // RealShell::SaveMenuItem
  1178. //------------------------------------------------------------------------------
  1179.  
  1180. void
  1181. RealShell::GetCurrentProcessInfo( ProcessInfoRec *info, StringPtr name, FSSpec *appLoc )
  1182. {
  1183.     ProcessSerialNumber psn = {0,kCurrentProcess};
  1184.     info->processInfoLength = sizeof(ProcessInfoRec);
  1185.     info->processName = name;
  1186.     info->processAppSpec = appLoc;
  1187.     THROW_IF_ERROR( GetProcessInformation(&psn,info) );
  1188. }
  1189.  
  1190.  
  1191. //------------------------------------------------------------------------------
  1192. // RealShell::SaveMenuItem
  1193. //------------------------------------------------------------------------------
  1194.  
  1195. void RealShell::SaveMenuItem(MenuHandle menu, short itemNum, MenuItemInfo* info)
  1196. {
  1197.     GetMenuItemText(menu, itemNum, (*info).text);
  1198.     GetItemCmd(menu, itemNum, &(*info).cmdChar);
  1199.     GetItemIcon(menu, itemNum, &(*info).iconID);
  1200.     GetItemMark(menu, itemNum, &(*info).markChar);
  1201.     GetItemStyle(menu, itemNum, &(*info).textStyle);
  1202. }
  1203.  
  1204. //------------------------------------------------------------------------------
  1205. // RealShell::RestoreMenuItem
  1206. //------------------------------------------------------------------------------
  1207.  
  1208. void RealShell::RestoreMenuItem(MenuHandle menu, short itemNum, MenuItemInfo* info)
  1209. {
  1210.     SetMenuItemText(menu, itemNum, (*info).text);
  1211.     SetItemCmd(menu, itemNum, (*info).cmdChar);
  1212.     SetItemIcon(menu, itemNum, (*info).iconID);
  1213.     SetItemMark(menu, itemNum, (*info).markChar);
  1214.     SetItemStyle(menu, itemNum, (*info).textStyle);
  1215. }
  1216.  
  1217. //------------------------------------------------------------------------------
  1218. // RealShell::InstallShellPlugIns
  1219. //------------------------------------------------------------------------------
  1220.  
  1221. void RealShell::InstallShellPlugIns(ODDraft* draft)
  1222. {
  1223.     // get reference to OpenDoc Shell PlugIns directory
  1224.     ODSShort fldrVRefNum=0;
  1225.     ODSLong fldrDirID=0;
  1226.  
  1227.     TRY{
  1228.         if (FindShellPlugInsFolder(&fldrVRefNum, &fldrDirID))
  1229.         this->ScanShellPlugInsFldr(fldrVRefNum, fldrDirID, draft);
  1230.     }CATCH_ALL{
  1231.         if ( fFailedPlugInName[0] )
  1232.             RERAISE;
  1233.     }ENDTRY
  1234.  
  1235. }
  1236.  
  1237. //------------------------------------------------------------------------------
  1238. // GetInstallEntryPt
  1239. // Given a file spec, find the record within the 'cfrg' resource in that
  1240. // file that corresponds to the platform we're on and the symbol we're
  1241. // looking for.  Loop through all entries until finding one that has
  1242. // the entry point we're looking for.
  1243. //------------------------------------------------------------------------------
  1244. ODStatic OSErr GetInstallEntryPt( ODFileSpec* fileSpec, ODShellPlugInInstallProc* entryPt,
  1245.         CFragConnectionID* connIDPtr )
  1246. {
  1247. #if PRAGMA_ALIGN_SUPPORTED
  1248. #pragma options align=mac68k
  1249. #endif
  1250.  
  1251.     struct FragDesc {
  1252.         ResType codeType;
  1253.         long ignore[5];
  1254.         long offsetToFrag;
  1255.         long lengthOfFrag;
  1256.         long moreIgnore[2];
  1257.         short recordLength;
  1258.         Str63 name;
  1259.     };
  1260.     
  1261.     struct CFRGResource {
  1262.         long ignore[7];
  1263.         long numFrags;
  1264.         struct FragDesc firstDesc;
  1265.     };
  1266.  
  1267. #if PRAGMA_ALIGN_SUPPORTED
  1268. #pragma options align=reset
  1269. #endif
  1270.  
  1271.     OSErr err = resNotFound;
  1272.  
  1273.     short refNum = HOpenResFile( fileSpec->vRefNum, fileSpec->parID,
  1274.             fileSpec->name, fsRdPerm );
  1275.     short saveRefNum = CurResFile();
  1276.     UseResFile( refNum );
  1277.  
  1278.     struct CFRGResource** cfrgHandle =
  1279.             (struct CFRGResource**)Get1Resource( 'cfrg', 0 );
  1280.     if ( cfrgHandle )
  1281.     {
  1282.         long entryCount = (*cfrgHandle)->numFrags;
  1283.         struct FragDesc* oneEntryPtr = &(*cfrgHandle)->firstDesc;
  1284.         while ( entryCount-- )
  1285.         {
  1286.             // for each fragment, if it's the right architecture
  1287.             // see if it has an entrypoint of the right name.
  1288.             // Keep going until found or all exhausted (bug 1322456)
  1289.             if ( oneEntryPtr->codeType == kCurrentCFragArch )
  1290.             {
  1291.                 CFragConnectionID connID;
  1292.                 Ptr ignoreMainAddr;
  1293.                 Str255 errName;
  1294.                 err = GetDiskFragment( fileSpec,
  1295.                         oneEntryPtr->offsetToFrag,
  1296.                         oneEntryPtr->lengthOfFrag,
  1297.                         NULL, kNewCFragCopy, &connID, &ignoreMainAddr,
  1298.                         errName );
  1299.                 if ( err == noErr )
  1300.                 {
  1301.                     ODShellPlugInInstallProc installMethod;
  1302.                     CFragSymbolClass symClass;
  1303.                     err = FindSymbol( connID, "\pODShellPlugInInstall",
  1304.                             (Ptr*)&installMethod, &symClass );
  1305.                     if ( err == noErr )            // we're done
  1306.                     {
  1307.                         WASSERT( symClass == kTVectorCFragSymbol );
  1308.                         *entryPt = installMethod;
  1309.                         *connIDPtr = connID;
  1310.                         break;
  1311.                     }
  1312.                     else    // we opened it but don't want it; free the memory
  1313.                         CloseConnection( &connID );
  1314.                 }
  1315.             }
  1316. //            else
  1317.                 oneEntryPtr = (FragDesc*)(oneEntryPtr->recordLength
  1318.                         + (char*)oneEntryPtr);
  1319.         }
  1320.     }
  1321.     else
  1322.         err = ResError();
  1323.  
  1324.     CloseResFile( refNum );
  1325.     UseResFile( saveRefNum );
  1326.     return err;
  1327. }    // GetInstallEntryPt()
  1328.  
  1329. //------------------------------------------------------------------------------
  1330. // RealShell::ScanShellPlugInsFldr
  1331. //------------------------------------------------------------------------------
  1332.  
  1333. void RealShell::ScanShellPlugInsFldr(ODSShort fldrVRefNum, ODSLong fldrDirID,
  1334.                                     ODDraft* draft)
  1335. {
  1336.     // iterate through files in that directory (code copied from Prefs.cpp:LoadNameSpaceTable)
  1337.     ODFileSpec        theFileSpec;
  1338.     CInfoPBRec        CinfoPB;
  1339.     Str255            fileName;
  1340.  
  1341.     memset (&CinfoPB,0,sizeof(CinfoPB));
  1342.     CinfoPB.hFileInfo.ioNamePtr = (StringPtr)fileName;
  1343.     CinfoPB.hFileInfo.ioFDirIndex = 1;
  1344.     CinfoPB.hFileInfo.ioVRefNum = fldrVRefNum;
  1345.     CinfoPB.hFileInfo.ioDirID = fldrDirID;
  1346.  
  1347.     TempPlatformFile file(new PlatformFile);
  1348.     
  1349.     for( ODSShort i = PBGetCatInfoSync( &CinfoPB ); 
  1350.                     i == noErr; 
  1351.                    i = PBGetCatInfoSync( &CinfoPB ) )
  1352.     {
  1353.             // if this is not a folder and we successfully create an FSSpec
  1354.         if (( ! (CinfoPB.hFileInfo.ioFlAttrib & (1<<4)) ) 
  1355.             && ( noErr == (FSMakeFSSpec( CinfoPB.hFileInfo.ioVRefNum, 
  1356.                               CinfoPB.hFileInfo.ioFlParID, //ioDirID, 
  1357.                               fileName, 
  1358.                               &theFileSpec ) ) ))
  1359.         {
  1360.             file->Specify(&theFileSpec);
  1361.             if ( file->GetPlatformType() == kCFragLibraryFileType)
  1362.             {
  1363.                 CFragConnectionID connID;
  1364.                 ODShellPlugInInstallProc installMethod;
  1365.                 OSErr err = GetInstallEntryPt( &theFileSpec,
  1366.                         &installMethod, &connID );
  1367.  
  1368.                 ODShellPlugInActionCodes action
  1369.                         = kODShellPlugInNoAction;
  1370.                 if ( !err )
  1371.                 {
  1372.                     TRY
  1373.                         err = (*installMethod)( fEV, draft, &action );
  1374.                     CATCH_ALL
  1375.                         SetErrorCode(kODNoError);
  1376.                     ENDTRY
  1377.                 }
  1378.                 // else is not a shell plugin; continue with next file
  1379.  
  1380.                 // test again; if the FindSymbol call failed we
  1381.                 // still want to close the connection
  1382.                 if ( (err != noErr) ||
  1383.                         BITTEST(action, kODShellPlugInCloseConnection) )
  1384.                     err = CloseConnection( &connID );
  1385.  
  1386.                 if ( err )
  1387.                 {
  1388.                     ODBlockMove( theFileSpec.name, fFailedPlugInName,
  1389.                             theFileSpec.name[0]+1 );
  1390.                     THROW( err );
  1391.                 }
  1392.             }
  1393.         }
  1394.         CinfoPB.hFileInfo.ioFDirIndex++;
  1395.                 
  1396.     //need to do this each time since PBGetCatInfo call returns val here
  1397.         CinfoPB.hFileInfo.ioNamePtr = (StringPtr)fileName;
  1398.         CinfoPB.hFileInfo.ioVRefNum = fldrVRefNum;
  1399.         CinfoPB.hFileInfo.ioDirID = fldrDirID;  
  1400.     }
  1401. }
  1402.  
  1403. //------------------------------------------------------------------------------
  1404. // FindShellPlugInsFolder
  1405. //
  1406. //    Return false if we can't find the folder.
  1407. //------------------------------------------------------------------------------
  1408.  
  1409. static ODBoolean FindShellPlugInsFolder(short *vol, long *dir )
  1410. {
  1411.     Str255        folderName;
  1412.     ODBoolean    result = kODFalse;
  1413.     
  1414.     CInfoPBRec        pb;
  1415.     memset (&pb,0,sizeof(pb));
  1416.  
  1417.         //First find System Folder
  1418.     THROW_IF_ERROR( FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, 
  1419.                                 &pb.dirInfo.ioVRefNum, &pb.dirInfo.ioDrDirID) );
  1420.  
  1421.         // find Shell Plug Ins Folder path name
  1422.     if ( FindOpenDocFolder(kOnSystemDisk, kOpenDocFolderType, kDontCreateFolder, 
  1423.                 vol, dir) == noErr)
  1424.         result = kODTrue;
  1425.     else
  1426.     {
  1427.         ODGetString(folderName, kODEditorsFldrStrID);
  1428.         pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1429.         pb.dirInfo.ioFDirIndex = 0;
  1430.         if( !PBGetCatInfoSync( &pb ) )
  1431.         {
  1432.             ODGetString(folderName, kODOpenDocPartsFolderStrID);
  1433.             pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1434.             pb.dirInfo.ioFDirIndex = 0;
  1435.             if ( !PBGetCatInfoSync( &pb ) )
  1436.             {
  1437.                 ODGetString(folderName, kODShellPlugInFolderStrID);
  1438.                 pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1439.                 pb.dirInfo.ioFDirIndex = 0;
  1440.                 if ( !PBGetCatInfoSync( &pb ) )
  1441.                 {
  1442.                     result = kODTrue;
  1443.                     *vol = pb.dirInfo.ioVRefNum;
  1444.                     *dir = pb.dirInfo.ioDrDirID;
  1445.                 }
  1446.             }
  1447.         }
  1448.     }
  1449.  
  1450.     return result;
  1451. }
  1452. //------------------------------------------------------------------------------
  1453. // FindStationeryFolder
  1454. //------------------------------------------------------------------------------
  1455. static void FindStationeryFolder(short *vol, long *dir )
  1456. {
  1457.     Str255    folderName;
  1458.     ODSLong    unused;
  1459.     
  1460.     CInfoPBRec        pb;
  1461.     memset (&pb,0,sizeof(pb));
  1462.  
  1463.         //First find Desktop Folder
  1464.     THROW_IF_ERROR( FindFolder(kOnSystemDisk, kDesktopFolderType, kDontCreateFolder, 
  1465.                                 vol, &unused ));
  1466.  
  1467.     if ( FindOpenDocFolder(*vol, kOpenDocStationeryFolderType, kCreateFolder, 
  1468.                 vol, dir) != noErr)
  1469.     {
  1470.         // find Stationery Folder path name
  1471.         ODGetString(folderName, kODStationeryFldrStrID);
  1472.         pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1473.         pb.dirInfo.ioDrDirID = fsRtDirID; //2;
  1474.         pb.dirInfo.ioVRefNum = *vol;
  1475.         pb.dirInfo.ioFDirIndex = 0;
  1476.         if ( PBGetCatInfoSync( &pb ) )
  1477.         {
  1478.             THROW_IF_ERROR( 
  1479.                 DirCreate(*vol, fsRtDirID, folderName, dir));
  1480.         } else {    
  1481.             *dir = pb.dirInfo.ioDrDirID;
  1482.         }
  1483.     }
  1484. }
  1485.  
  1486. //-------------------------------------------------------------------------------------
  1487. // RealShell::go
  1488. //-------------------------------------------------------------------------------------
  1489.  
  1490. void RealShell::go()
  1491. {
  1492.     ODBoolean    initialized;
  1493.     ODVolatile(initialized);
  1494.     ODULong        errorLoops = 0; // Counts the number of times in a row we caught
  1495.                                 //    an out-of-memory error in the event loop.
  1496.     ODVolatile(errorLoops);
  1497.     
  1498.     #if ODDebug
  1499.     if ( gDumpBlocksOnClose )
  1500.     {
  1501.         SetOutputMode(kWriteToFile);
  1502.         // MMBeginLeakChecking();
  1503.         // gLeakChecking = kODTrue;
  1504.         MMTrackStackCrawls( kODTrue );
  1505.     }
  1506.     #endif
  1507.     
  1508.     {
  1509.         TRY
  1510.             this->Initialize();
  1511.             initialized = kODTrue;
  1512.         CATCH_ALL
  1513.             initialized = kODFalse;
  1514. //            ODShellGenericGoodbye( ErrorCode() != kODErrAlreadyNotified );
  1515.             // OK, Looks like this call has been fixed. Let's try it.
  1516.             this->ExceptionAlert(ErrorCode(), ErrorMessage());
  1517.         ENDTRY
  1518.     }
  1519.     
  1520. #ifdef SHLTestErrorDialogUsage
  1521.     SHLDebugStr("\pPreErrorDialog HeapInfo…");
  1522.     HeapInfo();
  1523.     this->ExceptionAlert(1,kODNULL);
  1524. #endif
  1525.  
  1526. #ifdef SHLTestSessionOverhead
  1527.     SHLDebugStr("\pPreExtraSession HeapInfo…");
  1528.     HeapInfo();
  1529.  
  1530.     TRY
  1531.         TempODSession aSession = new ODSession;
  1532.         THROW_IF_NULL(aSession); // som objects don't autothrow if unable to allocate.
  1533.         aSession->InitSession(fEV);
  1534.     CATCH_ALL
  1535.     ENDTRY
  1536.  
  1537.     SHLDebugStr("\pPostExtraSession HeapInfo…");
  1538.     HeapInfo();
  1539. #endif
  1540.  
  1541.     EventRecord        eventRec;
  1542.     if (initialized)
  1543.     while (!fDispatcher->ShouldExit(fEV)) 
  1544.     {
  1545.         TRY
  1546.             gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  1547.             if ( gODBentoFatalErrorHasOccurred )
  1548.                 ODBentoFatalError(/*allowSuppress*/ kODFalse);
  1549.  
  1550.             if( this->CheckFileLocation() )            // Update if document renamed/moved
  1551.                 break;                                // we may need to quit if trashed
  1552.             
  1553.             ODSLong sleep = fDispatcher->GetSleepTime(fEV);
  1554.             if( sleep > kMaxTimeBetweenLocationChecks )
  1555.                 sleep = kMaxTimeBetweenLocationChecks;
  1556.             
  1557.             WaitNextEvent (everyEvent, &eventRec, sleep, fDispatcher->GetMouseRegion(fEV));
  1558.             if( eventRec.what == osEvt && (( eventRec.message >> 24 ) & 0x00FF)==0x01 )
  1559.                 fProcessIsActive= (eventRec.message & 0x01)!=0;
  1560.  
  1561.             // Need to have this before we process events because we may not have enough 
  1562.             // memory to process one.
  1563.             if( fProcessIsActive )
  1564.                 this->CheckFreeMemory();            // Display low-mem alert
  1565.     
  1566.             this->DispatchEvent((ODEventData*)&eventRec);
  1567.  
  1568.             this->CheckMenuBar();
  1569.     
  1570.         CATCH_ALL
  1571.  
  1572.             this->ExceptionAlert(ErrorCode(),ErrorMessage());
  1573.  
  1574.         ENDTRY
  1575.  
  1576.     }
  1577.     
  1578.     // Check to see if we failed in the odoc or oapp appleevent handlers.
  1579.     ODError    err = this->GetAEError();
  1580.     if (err)
  1581.     {
  1582.         this->ExceptionAlert(err,kODNULL);
  1583.     }
  1584. }
  1585.  
  1586.  
  1587. //-------------------------------------------------------------------------------------
  1588. // Notification Stuff
  1589. //-------------------------------------------------------------------------------------
  1590.  
  1591. struct NotEntry :public Link {
  1592.     RealShell::Notifier n;
  1593.     ODULong                refCon;
  1594.     NMRec                nm;
  1595.     
  1596.     virtual ~NotEntry( );
  1597. };
  1598.  
  1599. NotEntry::~NotEntry( )
  1600. {
  1601.     if( nm.nmIcon ) DisposeIconSuite(nm.nmIcon,kODTrue);
  1602. }
  1603.  
  1604. static ODIconFamily
  1605. GetRootPartIconFamily( Environment*    ev, ODSession* session )
  1606. {
  1607.     static ODIconFamily sIcon = kODNULL;
  1608.     if( !sIcon ) {
  1609.         TempODWindow odWindow = session->GetWindowState(ev)->AcquireFrontRootWindow(ev);
  1610.         ODFrame* rootFrame = odWindow ? odWindow->GetRootFrame(ev) : kODNULL;
  1611.         sIcon = ODGetIconFamily(ev, rootFrame);
  1612.     }
  1613.     return sIcon;
  1614. }
  1615.  
  1616.  
  1617. //-------------------------------------------------------------------------------------
  1618. // RealShell::Notify
  1619. //-------------------------------------------------------------------------------------
  1620.  
  1621. void
  1622. RealShell::Notify( RealShell::Notifier n, ODULong refCon )
  1623. {
  1624.     if( fProcessIsActive )
  1625.         (this->*n)( refCon );                        // We're active, so call notifier right now.
  1626.         
  1627.     else {
  1628.         NotEntry *e = new NotEntry;
  1629.         e->n = n;
  1630.         e->refCon = refCon;
  1631.         fNotifiers.AddLast(e);
  1632.         
  1633.         e->nm.qType = nmType;
  1634.         e->nm.nmMark = 1;                                    // Mark process menu
  1635.         e->nm.nmIcon = GetRootPartIconFamily(fEV, fSession);    // Show root part's icon
  1636.         e->nm.nmSound = (Handle)-1L;                        // Play system beep
  1637.         e->nm.nmStr = kODNULL;
  1638.         e->nm.nmResp = kODNULL;
  1639.         OSErr err= NMInstall(&e->nm);
  1640.         WASSERT(err==noErr);
  1641.     }
  1642. }
  1643.  
  1644.  
  1645. //-------------------------------------------------------------------------------------
  1646. // RealShell::CancelNotification
  1647. //-------------------------------------------------------------------------------------
  1648.  
  1649. void
  1650. RealShell::CancelNotification( RealShell::Notifier n )
  1651. {
  1652.     // Removes all notifications pointing to this notifier proc.
  1653.     NotEntry *next;
  1654.     for( NotEntry *e = (NotEntry*)fNotifiers.First(); e; e=next ) {
  1655.         next = (NotEntry*)fNotifiers.After(*e);
  1656.         if( e->n == n ) {
  1657.             NMRemove(&e->nm);
  1658.             fNotifiers.Remove(*e);
  1659.             delete e;
  1660.         }
  1661.     }
  1662. }
  1663.  
  1664.  
  1665. //-------------------------------------------------------------------------------------
  1666. // RealShell::ShowPendingNotification
  1667. //-------------------------------------------------------------------------------------
  1668.  
  1669. void
  1670. RealShell::ShowPendingNotifications( )
  1671. {
  1672.     if( fProcessIsActive ) {
  1673.         NotEntry *e;
  1674.         while( !fNotifiers.IsEmpty() ) {
  1675.             e = (NotEntry*) fNotifiers.RemoveFirst();
  1676.             NMRemove(&e->nm);
  1677.             (this->*(e->n))( e->refCon );                        // Call notifier method
  1678.             delete e;
  1679.         }
  1680.     }
  1681. }
  1682.  
  1683.  
  1684. //-------------------------------------------------------------------------------------
  1685. // RealShell::DispatchEvent
  1686. //-------------------------------------------------------------------------------------
  1687.  
  1688. void RealShell::DispatchEvent(ODEventData* event)
  1689. {
  1690.     switch (event->what)
  1691.     {
  1692.     case kODEvtMouseDown:    
  1693.         this->DispatchMouseDownEvent(event);                
  1694.         break;
  1695.                 
  1696.     case kODEvtMouseUp:
  1697.         this->DispatchMouseUpEvent(event);
  1698.         break;
  1699.  
  1700.     case kODEvtKeyDown:
  1701.         this->DispatchKeyDownEvent(event);                
  1702.         break;
  1703.                                     
  1704.     case kODEvtOS:
  1705.         // FOR NOW, EAT ALL ERRORS OCCURING DURING A SUSPEND.
  1706.         //    SEE WHAT TYPE OF OS EVENT IT IS
  1707.         ODUByte        typeOSEvent = (ODUByte) (event->message >> 24) & 0x00FF;
  1708.         ODBoolean    isSuspendEvent;
  1709.  
  1710.         //    IF IT'S A SUSPEND MESSAGE
  1711.         isSuspendEvent = ((typeOSEvent & suspendResumeMessage)
  1712.                             && (!(event->message & resumeFlag)));
  1713.         TRY
  1714.             fDispatcher->Dispatch(fEV,event);
  1715.             this->HandleOSEvent(event);
  1716.         CATCH_ALL
  1717.             if (isSuspendEvent)
  1718.                 WARN("Eating an error that occurred during suspend time.");
  1719.             else
  1720.                 RERAISE;
  1721.         ENDTRY
  1722.         break;
  1723.  
  1724.     case kHighLevelEvent:    
  1725.         if (!fDispatcher->Dispatch(fEV,event))
  1726.             this->HandleHighLevelEvent(event);                
  1727.         break;
  1728.         
  1729.     default:            
  1730.         fDispatcher->Dispatch(fEV,event);
  1731.         break;
  1732.     }
  1733. }
  1734.  
  1735. //-------------------------------------------------------------------------------------
  1736. // RealShell::DispatchMouseDownEvent
  1737. //-------------------------------------------------------------------------------------
  1738.  
  1739. void RealShell::DispatchMouseDownEvent(ODEventData* event)
  1740. {
  1741.     WindowPtr     theWindow = kODNULL;
  1742.     ODSShort     partCode = FindWindow(event->where, &theWindow);
  1743.  
  1744.     // Track the button state for protection against orphan
  1745.     // mouse-up events that can fall through a system floating
  1746.     // window (Apple Guide or Control Strip).  See kODEvtMouseUp
  1747.     // below.
  1748.     fMouseButtonIsDown        = kODTrue;
  1749.  
  1750.     if (partCode == kODMDInMenuBar)
  1751.         this->DispatchMenuEvent(event);
  1752.     else if (!(fDispatcher->Dispatch(fEV,event)) && theWindow)
  1753.         this->HandleMouseDownInWindow(theWindow, partCode, event);
  1754.  
  1755.     // If the mouse button has been released and there is no
  1756.     // mouseUp event waiting in the queue, assume it has been
  1757.     // consumed by the part and clear the mouse-down flag to
  1758.     // protect against pesky orphan mouse-ups that may follow.
  1759.     // First check to see if the mouse-down flag has already
  1760.     // been cleared (perhaps by reentrant calls to 
  1761.     // DispatchEvent, see bug 1400043).
  1762.     if ( fMouseButtonIsDown )
  1763.     {
  1764.         EventRecord ignoreEvent;
  1765.         fMouseButtonIsDown = ::StillDown() || ::EventAvail( mUpMask, &ignoreEvent );
  1766.     }
  1767. }
  1768.  
  1769.  
  1770. //-------------------------------------------------------------------------------------
  1771. // RealShell::DispatchMouseUpEvent
  1772. //-------------------------------------------------------------------------------------
  1773.  
  1774. void RealShell::DispatchMouseUpEvent(ODEventData* event)
  1775. {
  1776.     // If the we think the mouse button is down, dispatch the 
  1777.     // event and set the mouse button state to up.  Otherwise,
  1778.     // ignore the event because it is an orphan mouse-up
  1779.     // (See DisptachMouseDownEvent).
  1780.     if ( fMouseButtonIsDown )
  1781.     {
  1782.         fDispatcher->Dispatch( fEV, event );
  1783.         fMouseButtonIsDown = kODFalse;
  1784.     }
  1785. }
  1786.  
  1787.  
  1788. //-------------------------------------------------------------------------------------
  1789. // RealShell::DispatchMenuEvent
  1790. //-------------------------------------------------------------------------------------
  1791.  
  1792. void RealShell::DispatchMenuEvent(ODEventData* event)
  1793. {
  1794.     this->UpdateMenus();
  1795.     if (!(fDispatcher->Dispatch(fEV,event)))
  1796.         this->HandleMenuCommand(event->message, event);
  1797. }
  1798.  
  1799. //-------------------------------------------------------------------------------------
  1800. // RealShell::DispatchKeyDownEvent
  1801. //-------------------------------------------------------------------------------------
  1802. static ODBoolean EditFKeyDown( long message );
  1803. static ODBoolean EditFKeyDown( long message )
  1804. {
  1805.     if ( (message & charCodeMask) == 0x10 )
  1806.     {
  1807.         char keyCode = (message & keyCodeMask) >> 8;
  1808.         // aren't there constants for these keys anywhere?
  1809.         return (ODBoolean)(keyCode == 0x7A) || (keyCode == 0x78)
  1810.                 || (keyCode ==0x63) || (keyCode == 0x76);
  1811.     }
  1812.     return kODFalse;
  1813. }
  1814.  
  1815. void RealShell::DispatchKeyDownEvent(ODEventData* event)
  1816. {    
  1817.     ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  1818.     ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  1819.     if ( cmdKeyDown || EditFKeyDown(event->message) ) // || F1, f2, f3, f4 were pressed
  1820.         this->UpdateMenus();    
  1821.         // Fix #1221897
  1822.         // should also do update if function keys for Undo/Cut/Copy/Paste were pressed
  1823.  
  1824.     if ( !fDispatcher->Dispatch(fEV, event) )
  1825.     {
  1826.         if ( event->what == kODEvtMenu )
  1827.             this->HandleMenuCommand(event->message, event );
  1828.         else if ( cmdKeyDown && optionKeyDown )
  1829.         {
  1830.             // we have a command-key equivalent that didn't get recognized
  1831.             // because UI doesn't like the option key.  So we need to change
  1832.             // the character to what it would be without the option, then get
  1833.             // the equivalent menu and invoke its handler with the additional
  1834.             // information that the option key was down.
  1835.             
  1836.             // Adapted from Finder code furnished by Greg Anderson
  1837.             unsigned char key = event->message & charCodeMask;
  1838.             short mangledKeyCode = (short)((event->message & keyCodeMask) >> 8)
  1839.                     | (event->modifiers & keyCodeMask);  // raw key w/ all modifiers
  1840.             UInt32 state = 0;
  1841.             Ptr kchrCache = (Ptr)GetScriptManagerVariable(smKCHRCache);
  1842.             
  1843.             // Find out if the raw key code matches the character in event.message.
  1844.             unsigned char computedKey =        // only keep low byte
  1845.                     (unsigned char)KeyTranslate( kchrCache, mangledKeyCode,
  1846.                     &state );
  1847.                     
  1848.             if (computedKey == key)
  1849.             {
  1850.                 mangledKeyCode &= (0xFFFF - optionKey);    // mask out option bit
  1851.                 key = (unsigned char) KeyTranslate(kchrCache, mangledKeyCode, &state);
  1852.                 // only keep low byte; we'll use this new keycode w/o option.
  1853.  
  1854.                 // NOTE: I'm not changing the event, which HandleMenuCommand
  1855.                 // ignores anyway.
  1856. //                ODBoolean oldOptionValue = fOptionKeyDownOnMenuBarClick;
  1857.                 fOptionKeyDownOnMenuBarClick = kODTrue;            
  1858.                 this->HandleMenuCommand( MenuKey(key), event );
  1859. //                fOptionKeyDownOnMenuBarClick = oldOptionValue;
  1860.             }
  1861.         }
  1862.     }
  1863. }
  1864.  
  1865. //-------------------------------------------------------------------------------------
  1866. // RealShell::HandleOSEvent
  1867. //-------------------------------------------------------------------------------------
  1868.  
  1869. void RealShell::HandleOSEvent(ODEventData* event)
  1870. {
  1871.     // Is it a multifinder event?
  1872.     ODUByte typeOSEvent = (ODUByte) (event->message >> 24) & 0x00FF;
  1873.     
  1874.     // Switch on the type of OSEvent that occurred, high byte of message is event type
  1875.     switch (typeOSEvent) 
  1876.     {     
  1877.     case suspendResumeMessage:
  1878.         if( event->message & resumeFlag )
  1879.             this->ShowPendingNotifications();        // Display pending notifications
  1880.         else
  1881.             this->ExportClipboard(kODFalse);
  1882.         break;
  1883.     }
  1884. }
  1885.  
  1886. //-------------------------------------------------------------------------------------
  1887. // RealShell::ExportClipboard
  1888. //-------------------------------------------------------------------------------------
  1889.  
  1890. void RealShell::ExportClipboard(ODBoolean canAlert)
  1891. {
  1892.     if (fSession)
  1893.     {
  1894.         ODClipboard* clipboard = fSession->GetClipboard(fEV);
  1895.  
  1896.         if (clipboard)
  1897.             clipboard->ExportClipboard(fEV);
  1898.     }
  1899. }
  1900.  
  1901. //-------------------------------------------------------------------------------------
  1902. // Debug Menu Support
  1903. //-------------------------------------------------------------------------------------
  1904.  
  1905.  
  1906. #if ODDebugMenu
  1907.  
  1908. #define SKIPOMPARSE
  1909. #ifdef SKIPOMPARSE
  1910. extern "C" {
  1911. #endif
  1912.  
  1913.     #define kDumpTmpBufSize 3000
  1914.     
  1915.     static char gFilterNewClass; 
  1916.     // gFilterNewClass is a global with a unique address passed to DumpObjProc as refCon
  1917.     
  1918.     static MMBoolean DumpObjProc(  const void *blk, size_t size, MMBoolean isObject,
  1919.                                     void *refCon )
  1920.     {
  1921.         if( isObject ) {
  1922.             MMValidateObject((ODObject*)blk);
  1923.             somPrintf("  %p %4lu  %s\r", blk,size, ((ODObject*)blk)->somGetClassName());
  1924.         }
  1925.         return true;        // Might check for cmd-period or something to abort...
  1926.     }
  1927.     
  1928.     static void DumpBlockStackCrawl(  const void *blk, size_t size, ODBoolean isObject,
  1929.                                     ODBoolean filter )
  1930.     {
  1931.         long flags = 0;
  1932.         StackCrawl*    sc = MMGetBlockStackCrawl( blk, &flags );
  1933.         if (sc)
  1934.         {
  1935.             if ( !isObject )
  1936.             {
  1937.                 somPrintf("%p %4lu:\r", blk, size);
  1938.             }
  1939.             static const char* kTooLongString = "... [too long]\n";
  1940.             char buffer[kDumpTmpBufSize + 32]; // add 32 for kTooLongString
  1941.             buffer[0] = 0;
  1942.             long    numFrames = sc->CountFrames();
  1943.             long    pos = 0;
  1944.             for (long i = 0; i < numFrames && pos < kDumpTmpBufSize; i++)
  1945.             {
  1946.                 size_t    offset;
  1947.                 char    tmpBuffer[256];
  1948.                 char    fnName[256];
  1949.                 if (sc->LookupSymbol(i, fnName, &offset))
  1950.                 {
  1951.                     sprintf(tmpBuffer, "%s+%d\n", fnName, offset);
  1952.                     long newPos = pos + strlen(tmpBuffer);
  1953.                     if ( newPos < kDumpTmpBufSize )
  1954.                         sprintf(&(buffer[pos]), "%s", tmpBuffer);
  1955.                     else
  1956.                         strcpy(&(buffer[pos]), kTooLongString);
  1957.                     
  1958.                     pos = newPos;
  1959.                 } 
  1960.             }
  1961.             if ( filter )
  1962.             {
  1963.                 if ( buffer[0] && !strstr(buffer, "NewClass") )
  1964.                     somPrintf("%s\r", buffer);
  1965.             }
  1966.             else
  1967.             {
  1968.                 if ( buffer[0] )
  1969.                     somPrintf("%s\r", buffer);
  1970.             }
  1971.         }
  1972.     }
  1973.  
  1974. #ifdef SKIPOMPARSE
  1975. }
  1976. #endif
  1977.  
  1978.  
  1979. struct TrackedBlockLink {
  1980.     TrackedBlockLink* fNext;
  1981.     const void*          fFirstBlock;
  1982.     StackCrawl*       fStack;
  1983.     unsigned long      fCount;
  1984.     unsigned long      fTotalSize;
  1985. };
  1986.  
  1987. static TrackedBlockLink* sTrackedBlockLinks;
  1988.     
  1989. extern "C" {
  1990. static MMBoolean 
  1991. FindObjsProc(  const void *blk, size_t size, MMBoolean isObject, void *refCon )
  1992. {
  1993.     long flags;
  1994.     StackCrawl* s = MMGetBlockStackCrawl(blk, &flags);
  1995.     if( s ) {
  1996.         size_t blockSize = MMBlockSize(blk);
  1997.         
  1998.         // This is a new block, check its stack crawl:
  1999.         TrackedBlockLink *l;
  2000.         for( l = sTrackedBlockLinks; l; l = l->fNext )
  2001.             if( *(l->fStack) == *s ) {
  2002.                 l->fCount++;
  2003.                 l->fTotalSize += blockSize;
  2004.                 // delete s;
  2005.                 // MMSetBlockStackCrawl(blk,kODNULL,0);
  2006.                 return kODTrue;
  2007.             }
  2008.         l = new TrackedBlockLink;
  2009.         l->fNext = sTrackedBlockLinks;
  2010.         l->fFirstBlock = blk;
  2011.         l->fTotalSize = blockSize;
  2012.         l->fStack = s;
  2013.         l->fCount = 1;
  2014.         sTrackedBlockLinks = l;
  2015.     }
  2016.     return kODTrue;
  2017. }
  2018. }
  2019.  
  2020. static void 
  2021. DumpFoundObjs()
  2022. {
  2023.     unsigned long count = 0;
  2024.     unsigned long space = 0;
  2025.     TrackedBlockLink* next;
  2026.     ODBoolean filter = isFilterKeyDown();
  2027.     
  2028.     for( TrackedBlockLink * l = sTrackedBlockLinks; l; l = next ) {
  2029.         count += l->fCount;
  2030.         next = l->fNext;
  2031.         // if( l->fCount >= 3 ) {
  2032.             somPrintf("• Occurred %lu time%s, %lu total bytes:\r", 
  2033.                 l->fCount, (l->fCount == 1)? "": "s", l->fTotalSize);
  2034.             size_t size = MMBlockSize(l->fFirstBlock);
  2035.             ODBoolean isObject = MMIsObject(l->fFirstBlock);
  2036.             
  2037.             DumpObjProc(l->fFirstBlock, size, isObject, kODNULL);
  2038.             DumpBlockStackCrawl(l->fFirstBlock, size, isObject, filter);
  2039.             
  2040.             space += l->fTotalSize + (l->fCount * 8);    // Add 8 bytes for per-block overhead
  2041.         // }
  2042.         delete l;
  2043.     }
  2044.     sTrackedBlockLinks = kODNULL;
  2045.     if( space > 0 )
  2046.         somPrintf("••• Estimated space in %lu tracked blocks: %lu bytes\r", count, space);
  2047.     else
  2048.         somPrintf("••• No tracked blocks found!\r");
  2049. }    
  2050.  
  2051. static void
  2052. DumpHeapObjects( ODBoolean objectsOnly )
  2053. {
  2054.     const char *name;
  2055.     size_t allocated, free,blocks,objects;
  2056.     MMGetHeapInfo(kDefaultHeapID,
  2057.                     &name, &allocated, &free, &blocks, &objects);
  2058.     somPrintf("••• Dump of %s •••\r%lu bytes allocated, %lu free (%.1f%% free).\r",
  2059.                     name, (ODULong)allocated, (ODULong)free, 100.0*free/(float)(allocated+free) );
  2060.     somPrintf("There are %lu blocks, of which %lu are objects:\r", (ODULong)blocks, (ODULong)objects);
  2061.  
  2062.     if ( !objectsOnly && gTrackStackCrawls )
  2063.     {
  2064.         sTrackedBlockLinks = kODNULL;
  2065.  
  2066.         MMTrackStackCrawls(kODFalse); // disable stack crawls in FindObjsProc()
  2067.         MMWalkHeap(kDefaultHeapID, &FindObjsProc, kODNULL);
  2068.         DumpFoundObjs();
  2069.         MMTrackStackCrawls(kODTrue); // re-enable stack crawls
  2070.  
  2071.         sTrackedBlockLinks = kODNULL;
  2072.     }
  2073.     else
  2074.     {
  2075.         somPrintf("  ADDRESS  SIZE  CLASS\r");
  2076.         MMWalkHeap(kDefaultHeapID, &DumpObjProc, kODNULL);
  2077.     }
  2078. }
  2079.  
  2080.  
  2081. #endif
  2082.  
  2083. //-------------------------------------------------------------------------------------
  2084. // RealShell::HandleMenuCommand
  2085. //-------------------------------------------------------------------------------------
  2086.  
  2087.  
  2088. void RealShell::HandleMenuCommand(ODSLong menuResult, ODEventData* event)
  2089. {
  2090.     ODUnused(event);
  2091.  
  2092.     ODSShort menu = HiWord(menuResult);
  2093.     ODSShort item = LoWord(menuResult);
  2094.     TempODMenuBar menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  2095.     ODCommandID command = menuBar->GetCommand(fEV,menu, item);
  2096.  
  2097.     if (menuBar->IsCommandSynthetic(fEV,command))
  2098.     {
  2099.         switch (menu)
  2100.         {
  2101.             case kODAppleMenuID: // Apple
  2102.             {
  2103.                 Str255        daName;
  2104.                 ODSShort    daRefNum;
  2105.                 
  2106.                 GetMenuItemText(GetMenuHandle(kODAppleMenuID), item, daName);
  2107.                 daRefNum = OpenDeskAcc(daName);
  2108.                 HiliteMenu(0);
  2109.                 break;
  2110.             }
  2111.  
  2112.             default:
  2113.                 break;
  2114.         }
  2115.     }
  2116.     else 
  2117.     {
  2118.         ODDraft*        activeDraft  = ODGetActiveDraft(fEV, fSession);
  2119.         ODDocument*        activeDocument;
  2120.         if (activeDraft)
  2121.             activeDocument = activeDraft->GetDocument(fEV);
  2122.         else
  2123.             activeDocument = kODNULL;
  2124.         
  2125.         switch(command)
  2126.         {
  2127.             case kODCommandAbout: {
  2128.                 ShowAboutBox( fEV, fWindowState );
  2129.                 break;
  2130.             }
  2131.             
  2132. // POSSIBLE FIX NEEDED: needs to use activeDocument?
  2133.             case kODCommandNew:            delete (this->New());    break;
  2134.                     
  2135.             case kODCommandOpenDocument:    this->OpenStdFile();    break;
  2136.                 
  2137.             case kODCommandClose:
  2138.                 if (fOptionKeyDownOnMenuBarClick)
  2139.                 {
  2140.                     this->CloseDocument(activeDocument, kAEAsk);
  2141.                 } 
  2142.                 else
  2143.                 {
  2144.                     WindowPtr platformWindow = kODNULL;
  2145.                     {
  2146.                     TempODWindow window = ODAcquireActiveWindow(fEV, fSession);
  2147.                     if (window)
  2148.                         platformWindow = window->GetPlatformWindow(fEV);
  2149.                     }
  2150.                     this->CloseWindow(platformWindow, kAEAsk);
  2151.                 }
  2152.                 break;
  2153.  
  2154.             case kODCommandDeleteDocument:    this->DeleteDocument(activeDocument);    break;
  2155.             
  2156.             case kODCommandSave:            this->Save(activeDocument);                break;
  2157.                 
  2158.             case kODCommandSaveACopy:        this->SaveACopy(activeDraft);            break;
  2159.                 
  2160.             case kODCommandRevert:            this->Revert(activeDocument);            break;
  2161.                 
  2162.             case kODCommandDraft:            this->Drafts(activeDocument);            break;
  2163.                     
  2164.             case kODCommandDocumentInfo:    this->DocumentInfo(activeDocument);        break;
  2165.             
  2166. #ifdef SUPPORT_QUIT
  2167.             case kODCommandQuit:            this->CloseAllDocs(kAEAsk);                break;
  2168. #endif                    
  2169.             case kODCommandUndo:    fSession->GetUndo(fEV)->Undo(fEV);        break;
  2170.  
  2171.             case kODCommandRedo:    fSession->GetUndo(fEV)->Redo(fEV);        break;
  2172.  
  2173.             // case kODCommandGetPartInfo:        this->PartInfo();        break;
  2174.  
  2175. #if ODDebugMenu
  2176.             case kODCommandDBHeapInfo: {
  2177.                 HeapInfo();
  2178.                 break;
  2179.             }
  2180.             case kODCommandDBDumpObjects:
  2181.                 DumpHeapObjects( /*objectsOnly*/ kODTrue );
  2182.                 break;
  2183.             case kODCommandDBDumpBlocks:
  2184.                 DumpHeapObjects( /*objectsOnly*/ kODFalse );
  2185.                 break;
  2186.             case kODCommandDBMemValidation:
  2187.                 if( gMemValidation ) {
  2188.                     if( gHeapChecking ) {            // When turning off validation,
  2189.                         MMEndHeapChecking();        // turn heap checking off too
  2190.                         gHeapChecking = kODFalse;
  2191.                     }
  2192.                     MMEndMemValidation();
  2193.                     gMemValidation = kODFalse;
  2194.                 } else {
  2195.                     MMBeginMemValidation();
  2196.                     gMemValidation = kODTrue;
  2197.                 }
  2198.                 break;
  2199.             case kODCommandDBHeapChecking:
  2200.                 if( gHeapChecking ) {
  2201.                     MMEndHeapChecking();
  2202.                     gHeapChecking = kODFalse;
  2203.                 } else {
  2204.                     MMBeginMemValidation();            // When turning on heap checking,
  2205.                     gMemValidation = kODTrue;        // turn validation on too
  2206.                     MMBeginHeapChecking();
  2207.                     gHeapChecking = kODTrue;
  2208.                 }
  2209.                 break;
  2210.             case kODCommandDBLeakChecking:
  2211.                 if( gLeakChecking )
  2212.                     MMEndLeakChecking();
  2213.                 else
  2214.                     MMBeginLeakChecking();
  2215.                 gLeakChecking = !gLeakChecking;
  2216.                 gTrackStackCrawls = gLeakChecking;
  2217.                 break;
  2218.             case kODCommandDBDumpBlocksOnClose:
  2219.                 gDumpBlocksOnClose = !gDumpBlocksOnClose;
  2220.                 break;
  2221.             case kODCommandDBTrackStackCrawls:
  2222.                 if( gTrackStackCrawls )
  2223.                     MMTrackStackCrawls( kODFalse );
  2224.                 else
  2225.                     MMTrackStackCrawls( kODTrue );
  2226.                 gTrackStackCrawls = !gTrackStackCrawls;
  2227.                 break;
  2228.             case kODCommandDBEatMemory:
  2229.                 (void) NewHandle(32*1024);            // For testing low-mem survival!
  2230.                 if( MemError() ) {
  2231.                     SysBeep(3);
  2232.                     WARN("Error %d eating memory!;ht",MemError());
  2233.                 }
  2234.                 break;
  2235.             case kODCommandDBPurge:
  2236.                 this->Purge(10*1024*1024);
  2237.                 break;
  2238.             case kODCommandDBLogStdout:
  2239.                 if( GetOutputMode() != kWriteToFile )
  2240.                     SetOutputMode(kWriteToFile);
  2241.                 else
  2242.                     SetOutputMode(kNoOutput);
  2243.                 break;
  2244.             case kODCommandDBLogDebugWindow:
  2245.                 if( GetOutputMode() != kWriteToDebugWindow )
  2246.                     SetOutputMode(kWriteToDebugWindow);
  2247.                 else
  2248.                     SetOutputMode(kNoOutput);
  2249.                 break;
  2250.             case kODCommandDBLogDebugStr:
  2251.                 if( GetOutputMode() != kGenerateDebugStrs )
  2252.                     SetOutputMode(kGenerateDebugStrs);
  2253.                 else
  2254.                     SetOutputMode(kNoOutput);
  2255.                 break;
  2256.             case kODCommandDBBreakOnThrow:
  2257.                 BreakOnThrow( ! BreakOnThrow(kODFalse) );
  2258.                 // This looks weird, but we have to call it once to get the
  2259.                 // old value, then again to set it to the opposite of that.
  2260.                 break;
  2261.             case kODCommandDBSOMTrace:
  2262.                 SOM_TraceLevel = !SOM_TraceLevel;
  2263.                 break;
  2264. #endif
  2265.  
  2266.             default:
  2267.                 // some part enabled a menu command but did not handle it
  2268.                 break;
  2269.         }
  2270.         HiliteMenu(0);
  2271.     } 
  2272. }
  2273.  
  2274. //-------------------------------------------------------------------------------------
  2275. // RealShell::HandleMouseDownInWindow
  2276. //-------------------------------------------------------------------------------------
  2277.  
  2278. void RealShell::HandleMouseDownInWindow(WindowPtr pwindow, ODSShort partCode, ODEventData* event)
  2279. {
  2280.     switch (partCode)
  2281.     {
  2282.     case kODMDInGoAway:    
  2283.         this->HandleMouseDownInCloseBox(pwindow, event);            
  2284.         break;
  2285.  
  2286.     case kODMDInDrag:        
  2287.         this->HandleMouseDownInDragRegion(pwindow, event);            
  2288.         break;
  2289.         
  2290.     case kODMDInGrow:        
  2291.         this->HandleMouseDownInGrowBox(pwindow, event);            
  2292.         break;
  2293.                         
  2294.     case kODMDInZoomIn:
  2295.     case kODMDInZoomOut:    
  2296.         this->HandleMouseDownInZoomBox(pwindow, partCode,event);    
  2297.         break;
  2298.         
  2299.     case kODMDInContent:
  2300.         {
  2301.             // This section used to select windows.
  2302.             // Parts must be responsible for window selection so that
  2303.             // the modal focus is respected.
  2304.             // Also, according to recipes, window selection should only
  2305.             // occur on mouse-up, anyway.
  2306.             TempODWindow window = fWindowState->AcquireODWindow(fEV,pwindow);
  2307.             if ( window != kODNULL )
  2308.             {
  2309.                 if ( !window->IsActive( fEV ))
  2310.                 {
  2311.                     SysBeep( 2 );
  2312.                 }
  2313.             }
  2314.             else if ( ((WindowPeek)pwindow)->hilited == kODFalse )
  2315.             {
  2316.                 WARN("This window is not registered with OpenDoc!");
  2317.                 SysBeep( 2 );
  2318.             }
  2319.         }
  2320.         break;
  2321.     default:                
  2322.         break;
  2323.     }
  2324. }
  2325.  
  2326. //-------------------------------------------------------------------------------------
  2327. // RealShell::HandleMouseDownInCloseBox
  2328. //-------------------------------------------------------------------------------------
  2329.  
  2330. void RealShell::HandleMouseDownInCloseBox(WindowPtr pwindow, ODEventData* event)
  2331. {
  2332.     if (TrackGoAway (pwindow, event->where))
  2333.     {
  2334.         if (IsOptionKeyDown())
  2335.         {    
  2336.             ODDocument* document = kODNULL;
  2337.             {
  2338.             TempODWindow     window = fWindowState->AcquireODWindow(fEV, pwindow);
  2339.             WASSERT(window != kODNULL);
  2340.             document = ODGetDraftOfWindow(fEV, window)->GetDocument(fEV);
  2341.             }
  2342.             this->CloseDocument(document, kAEAsk);
  2343.         }
  2344.         else
  2345.             this->CloseWindow(pwindow, kAEAsk);
  2346.     }
  2347.     fMouseButtonIsDown = kODFalse;        // TrackGoAway eats mouse-ups
  2348. }
  2349.  
  2350. //-------------------------------------------------------------------------------------
  2351. // RealShell::HandleMouseDownInDragRegion
  2352. //-------------------------------------------------------------------------------------
  2353.  
  2354. void RealShell::HandleMouseDownInDragRegion(WindowPtr platformWindow, ODEventData* event)
  2355. {
  2356.     TempODWindow     window = fWindowState->AcquireODWindow(fEV,platformWindow);
  2357.     if (window != kODNULL) 
  2358.     {
  2359.         if ( window->IsActive( fEV ) || !this->IsSessionModal())
  2360.         {
  2361.             window->Drag(fEV, &event->where, (Rect*)&ODQDGlobals.screenBits.bounds);
  2362.             fMouseButtonIsDown = kODFalse;        // Drag eats mouse-ups
  2363.         }
  2364.         else
  2365.             SysBeep( 2 );
  2366.     }
  2367.     else 
  2368.     {
  2369.         if ( ((WindowPeek)platformWindow)->hilited || !this->IsSessionModal())
  2370.         {
  2371.             WARN("Dragging non-ODWindow.");
  2372.             DragWindow(platformWindow, event->where, &(ODQDGlobals.screenBits.bounds));
  2373.             fMouseButtonIsDown = kODFalse;        // DragWindow eats mouse-ups
  2374.         }
  2375.         else
  2376.             SysBeep( 2 );
  2377.     }
  2378.  
  2379. }
  2380.  
  2381. //-------------------------------------------------------------------------------------
  2382. // RealShell::HandleMouseDownInGrowBox
  2383. //-------------------------------------------------------------------------------------
  2384.  
  2385. void RealShell::HandleMouseDownInGrowBox(WindowPtr pwindow, ODEventData* event)
  2386. {
  2387.     if (!fWindowState->IsODWindow(fEV,pwindow))
  2388.         return;
  2389.     
  2390.     TempODWindow window = fWindowState->AcquireODWindow(fEV,pwindow);
  2391.  
  2392.     if (window == kODNULL)
  2393.         return;
  2394.         
  2395.     if (window->IsResizable(fEV))
  2396.     {
  2397.         Rect growLimits; //  = ODQDGlobals.screenBits.bounds);
  2398.         
  2399.         ODRgnHandle contRgn = 
  2400.             ((WindowRecord*)(window->GetPlatformWindow(fEV)))->contRgn;
  2401.         Rect currentBounds = (**contRgn).rgnBBox;
  2402.  
  2403.         window->GetWindowBounds(fEV, ¤tBounds);
  2404.         
  2405.         growLimits.left = currentBounds.right-currentBounds.left;
  2406.         if (growLimits.left > kMinWindowWidth)
  2407.             growLimits.left = kMinWindowWidth;
  2408.         growLimits.top = currentBounds.bottom-currentBounds.top;
  2409.         if (growLimits.top > kMinWindowHeight)
  2410.             growLimits.top = kMinWindowHeight;
  2411.             
  2412.         growLimits.right = kMaxWindowWidth;
  2413.         growLimits.bottom = kMaxWindowHeight;
  2414.         
  2415.         ODSLong newWindowSize = GrowWindow(pwindow, event->where, &growLimits);
  2416.         fMouseButtonIsDown = kODFalse;        // GrowWindow eats mouse-ups
  2417.         SizeWindow(pwindow, LoWord(newWindowSize), HiWord(newWindowSize), true);
  2418.     
  2419.         window->AdjustWindowShape(fEV);
  2420.     
  2421.         Rect r = pwindow->portRect;
  2422.         r.left = r.right  - 15;
  2423.         r.top  = r.bottom - 15;
  2424.         RgnHandle    oldClip = nil;
  2425.         GetClip(oldClip = ODNewRgn());
  2426.         ClipRect(&r);
  2427.         DrawGrowIcon(pwindow);
  2428.         SetClip(oldClip);
  2429.         ODDisposeHandle((Handle)oldClip);
  2430.     }
  2431. }
  2432.  
  2433. //-------------------------------------------------------------------------------------
  2434. // RealShell::HandleMouseDownInZoomBox
  2435. //-------------------------------------------------------------------------------------
  2436.  
  2437. void RealShell::HandleMouseDownInZoomBox(WindowPtr pwindow, ODSShort partcode, ODEventData* event)
  2438. {
  2439.     if (TrackBox(pwindow, event->where, partcode))
  2440.     {
  2441.         TempODWindow  window = kODNULL;
  2442.         
  2443.         if (fWindowState->IsODWindow(fEV,pwindow))
  2444.             window = fWindowState->AcquireODWindow(fEV,pwindow);
  2445.         
  2446.         GrafPtr port;
  2447.         GetPort(&port);
  2448.         SetPort(pwindow);
  2449.         
  2450.         ZoomWindow(pwindow, partcode, kODFalse);
  2451.         
  2452.         SetPort(port);
  2453.         
  2454.         if (window)
  2455.             window->AdjustWindowShape(fEV);
  2456.     }
  2457.     fMouseButtonIsDown = kODFalse;        // TrackBox eats mouse-ups
  2458. }
  2459.  
  2460. //-------------------------------------------------------------------------------------
  2461. // RealShell::IsSessionModal
  2462. //-------------------------------------------------------------------------------------
  2463.  
  2464. ODBoolean RealShell::IsSessionModal()
  2465. {
  2466.     TempODFrame modalFocus = fArbitrator->AcquireFocusOwner( fEV, fModalFocusToken );    
  2467.     return modalFocus != kODNULL;
  2468. }
  2469.  
  2470. //-------------------------------------------------------------------------------------
  2471. // RealShell::UpdateMenus
  2472. //-------------------------------------------------------------------------------------
  2473.  
  2474. void RealShell::UpdateMenus()
  2475. {
  2476.     ODIText*        menuItem;
  2477.     TempODMenuBar    menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  2478.     MenuHandle        appleMenu = menuBar->GetMenu(fEV, kODAppleMenuID);
  2479.     MenuHandle        editMenu = menuBar->GetMenu(fEV, kODEditMenuID);
  2480.     ODDocument*        activeDocument = ODGetActiveDocument(fEV, fSession);
  2481.  
  2482.     fOptionKeyDownOnMenuBarClick = IsOptionKeyDown();
  2483.     
  2484. // Menu items which require resources:
  2485.     { CUsingLibraryResources r;
  2486.     
  2487.     // About Menu item
  2488.         this->RestoreMenuItem(appleMenu, kSHLMenuAbout, &fDefaultAboutMenuItem);
  2489.  
  2490.     //== Document-wide menu items
  2491.         Str255 targetName;
  2492.         if (activeDocument)
  2493.         {
  2494.             TempPlatformFile    file = 
  2495.                 GetPlatformFileFromContainer(fEV, activeDocument->GetContainer(fEV));                            
  2496.     
  2497.             file->GetAsciiName( (char*)targetName, sizeof(targetName) );
  2498.             CToPascalString((char*)targetName);
  2499.         }
  2500.         else
  2501.         {
  2502.             targetName[0] = 0;
  2503.         }
  2504.         Str255 destString;
  2505.         
  2506.     // Delete Menu item
  2507.         ReplaceIntoString( kSHLDeleteItemTemplateStrID, targetName, kODNULL,
  2508.                 destString );
  2509.         menuItem = CreateDefaultIText(destString);
  2510.         menuBar->SetItemString(fEV, kODCommandDeleteDocument, menuItem);
  2511.         DisposeIText(menuItem);
  2512.  
  2513.     // Save Menu item
  2514.         ReplaceIntoString( kSHLSaveItemTemplateStrID, targetName, kODNULL,
  2515.                 destString );
  2516.         menuItem = CreateDefaultIText(destString);
  2517.         menuBar->SetItemString(fEV, kODCommandSave, menuItem);
  2518.         DisposeIText(menuItem);
  2519.  
  2520.     // Close Menu item
  2521.         if ( !IsOptionKeyDown() )        // close the whole document
  2522.         {
  2523.             TempODWindow window = ODAcquireActiveWindow(fEV, fSession);
  2524.             ODPlatformWindow pwin = window ?
  2525.                     window->GetPlatformWindow(fEV) : kODNULL;
  2526.             if ( pwin )
  2527.                 GetWTitle( pwin, targetName );
  2528.             else
  2529.                 targetName[0] = '\0';
  2530.         }
  2531.  
  2532.         ReplaceIntoString( kSHLCloseItemTemplateStrID, targetName, kODNULL,
  2533.                 destString );
  2534.         menuItem = CreateDefaultIText(destString);
  2535.         menuBar->SetItemString(fEV, kODCommandClose, menuItem);
  2536.         DisposeIText(menuItem);
  2537.  
  2538.     // Part Info menu item
  2539.         menuItem = GetODITextInd(kSHLStrsID, kSHLStrIndMPartInfo);
  2540.         menuBar->SetItemString(fEV, kODCommandGetPartInfo, menuItem);
  2541.         DisposeIText(menuItem);
  2542.         }
  2543.     menuBar->EnableCommand(fEV, kODCommandAbout, kODTrue);
  2544.     menuBar->EnableCommand(fEV, kODCommandClose, kODTrue);
  2545.     menuBar->EnableCommand(fEV, kODCommandGetPartInfo, kODFalse);
  2546.     
  2547. // Document Menu
  2548.  
  2549.     menuBar->EnableCommand(fEV, kODCommandNew, kODTrue);
  2550.     menuBar->EnableCommand(fEV, kODCommandOpen, kODFalse);
  2551.     menuBar->EnableCommand(fEV, kODCommandOpenDocument, kODTrue);
  2552.     menuBar->EnableCommand(fEV, kODCommandInsert, kODFalse);            
  2553.     menuBar->EnableCommand(fEV, kODCommandDeleteDocument, 
  2554.             ODDocumentHasWriteAccess(fEV, fSession, activeDocument));            
  2555.  
  2556.     ODBoolean unsavedChanges = ODDocumentHasChanges(fEV, fSession, activeDocument);
  2557.     menuBar->EnableCommand(fEV, kODCommandSave, unsavedChanges);
  2558.     menuBar->EnableCommand(fEV, kODCommandSaveACopy, kODTrue);
  2559.     menuBar->EnableCommand(fEV, kODCommandRevert, unsavedChanges);
  2560.  
  2561.     menuBar->EnableCommand(fEV, kODCommandDraft,  kODTrue);
  2562.     menuBar->EnableCommand(fEV, kODCommandDocumentInfo, kODTrue);
  2563.     menuBar->EnableCommand(fEV, kODCommandPageSetup, kODFalse);
  2564.     menuBar->EnableCommand(fEV, kODCommandPrint, kODFalse);
  2565.  
  2566. #ifdef SUPPORT_QUIT
  2567.     if( fAPPLProcess )
  2568.         menuBar->EnableCommand(fEV, kODCommandQuit, kODTrue);
  2569. #endif
  2570.  
  2571. // Edit Menu
  2572.  
  2573.     this->UpdateUndoMenus();
  2574.  
  2575.     menuBar->EnableCommand(fEV, kODCommandCut, kODFalse);
  2576.     menuBar->EnableCommand(fEV, kODCommandCopy, kODFalse);
  2577.     menuBar->EnableCommand(fEV, kODCommandPaste, kODFalse);
  2578.     menuBar->EnableCommand(fEV, kODCommandPasteAs, kODFalse);
  2579.     menuBar->EnableCommand(fEV, kODCommandClear, kODFalse);
  2580.     menuBar->EnableCommand(fEV, kODCommandSelectAll, kODFalse);
  2581.  
  2582.     menuBar->EnableCommand(fEV, kODCommandPreferences , kODFalse);
  2583.     menuBar->EnableCommand(fEV, kODCommandViewAsWin, kODFalse);
  2584.  
  2585.     if ( editMenu )
  2586.     {
  2587.         ODMenuID prefMenuID;
  2588.         ODMenuItemID prefMenuItem;
  2589.         menuBar->GetMenuAndItem(fEV, kODCommandPreferences, &prefMenuID, &prefMenuItem);
  2590.         this->RestoreMenuItem(editMenu, prefMenuItem, &fDefaultPrefsMenuItem);
  2591.     }
  2592.  
  2593. #if ODDebugMenu
  2594.     DebugOutputMode outMode = GetOutputMode();
  2595.     ODBoolean breakingOnThrow = BreakOnThrow(kODFalse);
  2596.     BreakOnThrow(breakingOnThrow);    // Have to reset original value...
  2597.     menuBar->EnableCommand(fEV, kODCommandDBDumpObjects,    outMode!=kNoOutput);
  2598.     menuBar->EnableCommand(fEV, kODCommandDBDumpBlocks,    gTrackStackCrawls>0 && outMode!=kNoOutput);
  2599.     menuBar->CheckCommand(fEV, kODCommandDBMemValidation,    gMemValidation>0);
  2600.     menuBar->CheckCommand(fEV, kODCommandDBHeapChecking,    gHeapChecking>0);
  2601.     menuBar->EnableCommand(fEV, kODCommandDBLeakChecking,    outMode!=kNoOutput);
  2602.     menuBar->CheckCommand(fEV, kODCommandDBLeakChecking,    gLeakChecking>0);
  2603.     menuBar->EnableCommand(fEV, kODCommandDBDumpBlocksOnClose,    outMode!=kNoOutput);
  2604.     menuBar->CheckCommand(fEV, kODCommandDBDumpBlocksOnClose,    gDumpBlocksOnClose>0);
  2605.     menuBar->EnableCommand(fEV, kODCommandDBTrackStackCrawls,    kODTrue);
  2606.     menuBar->CheckCommand(fEV, kODCommandDBTrackStackCrawls,    gTrackStackCrawls>0);
  2607.     menuBar->CheckCommand(fEV, kODCommandDBLogStdout,        outMode==kWriteToFile);
  2608.     menuBar->CheckCommand(fEV, kODCommandDBLogDebugWindow,    outMode==kWriteToDebugWindow);
  2609.     menuBar->CheckCommand(fEV, kODCommandDBLogDebugStr,    outMode==kGenerateDebugStrs);
  2610.     menuBar->CheckCommand(fEV, kODCommandDBBreakOnThrow,    breakingOnThrow);
  2611.     menuBar->CheckCommand(fEV, kODCommandDBSOMTrace,        SOM_TraceLevel!=0);
  2612. #endif
  2613.  
  2614.     // Let the parts have the last crack at the menus.
  2615.     fWindowState->AdjustPartMenus(fEV);
  2616. }
  2617.  
  2618. //------------------------------------------------------------------------------
  2619. // RealShell::CheckMenuBar
  2620. //------------------------------------------------------------------------------
  2621.  
  2622. void RealShell::CheckMenuBar()
  2623. {
  2624.     ODBoolean shellHadMenuFocus = fShellHasMenuFocus;
  2625.     ODTypeToken menuFocus = fSession->Tokenize(fEV, kODMenuFocus);
  2626.     TempODFrame focusFrame = fSession->GetArbitrator(fEV)->AcquireFocusOwner(fEV, menuFocus);
  2627.     fShellHasMenuFocus = (focusFrame == kODNULL);
  2628.  
  2629.     if (fShellHasMenuFocus && !shellHadMenuFocus)
  2630.     {
  2631.         TempODMenuBar baseMenuBar = fWindowState->AcquireBaseMenuBar(fEV);
  2632.         if (baseMenuBar)
  2633.             baseMenuBar->Display(fEV);
  2634.     }
  2635. }
  2636.     
  2637. //------------------------------------------------------------------------------
  2638. // RealShell::UpdateUndoMenus
  2639. //------------------------------------------------------------------------------
  2640.  
  2641. void RealShell::UpdateUndoMenus()
  2642. {
  2643.     ODUndo*            undo = fSession->GetUndo(fEV);
  2644.     ODPart*            part;
  2645.     ODActionData    actionData;
  2646.     ODActionType    actionType;
  2647.     ODName            actionLabel;
  2648.  
  2649.     ODVolatile(actionLabel);
  2650.     ODVolatile(actionData);
  2651.  
  2652.     actionLabel.text._buffer = kODNULL;
  2653.     actionData._buffer = kODNULL;
  2654.  
  2655.     TRY
  2656.         TempODMenuBar    menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  2657.         MenuHandle        editMenu = menuBar->GetMenu(fEV, kODEditMenuID);
  2658.  
  2659.         // these IsCommandRegistered calls are to prevent ResetUndoText from
  2660.         // being called with a null menu, which is what you get at least
  2661.         // in the EditorSetup case.  Other cases might not be detected
  2662.  
  2663.         if (undo->PeekUndoHistory(fEV, &part, &actionData, &actionType,
  2664.                                     &actionLabel))
  2665.         {
  2666.             menuBar->EnableCommand(fEV, kODCommandUndo, kODTrue);
  2667.             menuBar->SetItemString(fEV, kODCommandUndo, &actionLabel);
  2668.         }
  2669.         else
  2670.         {
  2671.             menuBar->EnableCommand(fEV, kODCommandUndo, kODFalse);
  2672.             this->ResetUndoText(editMenu);
  2673.         }
  2674.     
  2675.         DisposeITextStruct(actionLabel);
  2676.         DisposeByteArrayStruct(actionData);
  2677.         actionLabel.text._buffer = kODNULL;
  2678.         actionData._buffer = kODNULL;
  2679.  
  2680.         if (undo->PeekRedoHistory(fEV, &part, &actionData, &actionType,
  2681.                                     &actionLabel))
  2682.         {
  2683.             menuBar->EnableCommand(fEV, kODCommandRedo, kODTrue);
  2684.             menuBar->SetItemString(fEV, kODCommandRedo, &actionLabel);
  2685.         }
  2686.         else
  2687.         {
  2688.             menuBar->EnableCommand(fEV, kODCommandRedo, kODFalse);
  2689.             this->ResetRedoText(editMenu);
  2690.         }
  2691.     CATCH_ALL
  2692.         if (actionLabel.text._buffer)
  2693.             DisposeITextStruct(actionLabel);
  2694.         if (actionData._buffer)
  2695.             DisposeByteArrayStruct(actionData);
  2696.         RERAISE;
  2697.     ENDTRY
  2698.  
  2699.     DisposeITextStruct(actionLabel);
  2700.     DisposeByteArrayStruct(actionData);
  2701. }
  2702.  
  2703.  
  2704. //-------------------------------------------------------------------------------------
  2705. // RealShell::ResetUndoText
  2706. //-------------------------------------------------------------------------------------
  2707.  
  2708. void RealShell::ResetUndoText(MenuHandle editMenu)
  2709. {
  2710.     if ( editMenu )
  2711.         this->RestoreMenuItem(editMenu, kSHLMenuUndo, &fDefaultUndoMenuItem);
  2712. }
  2713.  
  2714. //-------------------------------------------------------------------------------------
  2715. // RealShell::ResetRedoText
  2716. //-------------------------------------------------------------------------------------
  2717.  
  2718. void RealShell::ResetRedoText(MenuHandle editMenu)
  2719. {
  2720.     if ( editMenu )
  2721.         this->RestoreMenuItem(editMenu, kSHLMenuRedo, &fDefaultRedoMenuItem);
  2722. }
  2723.  
  2724. //-------------------------------------------------------------------------------------
  2725. // New
  2726. //-------------------------------------------------------------------------------------
  2727.  
  2728. PlatformFile*    RealShell::New()
  2729. {
  2730.     // create another container, create a root part of the same kind and editor
  2731.     // as the root part of the active window
  2732.  
  2733.     TempODType         rootPartType    = kODNULL;
  2734.     TempODEditor    editor            = kODNULL;
  2735.     TempODName        category        = kODNULL;
  2736.     ODStorageUnit*    psu                = kODNULL;
  2737.     PlatformFile*     newFile            = new PlatformFile();
  2738.  
  2739.     TempODWindow    window = ODAcquireActiveWindow(fEV, fSession);
  2740.     if (window)
  2741.     {
  2742.         TempODPart part = window->GetRootFrame(fEV)->AcquirePart(fEV);
  2743.         ASSERT((ODPart*)part != kODNULL, kODErrNoDraftProperties);  
  2744.             // !!!!! Should probably have its own errorcode, even though the user
  2745.             // error message will be the same.
  2746.         category = ODGetCategory(fEV, part, fSession->GetNameSpaceManager(fEV));    
  2747.         psu = part->GetStorageUnit(fEV);
  2748.     }
  2749.     
  2750.     if (psu &&
  2751.         psu->Exists(fEV, kODPropContents, (ODValueType)kODNULL, (ODValueIndex)kODNULL)) 
  2752.     {
  2753.         psu->Focus(fEV, kODPropContents, kODPosSame, (ODValueType)kODNULL,1, kODPosFirstSib);
  2754.         rootPartType = psu->GetType(fEV);
  2755.         editor = (ODEditor)ODGetISOStrProp(fEV, psu, kODPropPreferredEditor, kODEditor, kODNULL, kODNULL);
  2756.  
  2757.         TempPlatformFile    file = GetPlatformFileFromContainer(fEV,
  2758.                                     psu->GetDraft(fEV)->GetDocument(fEV)->GetContainer(fEV));
  2759.         newFile->SpecifyFromFile(file);
  2760.     }
  2761.  
  2762.     {
  2763.     ODContainer*    container;
  2764.     CreateUntitledContainer(kODNULL, &container, newFile, category);
  2765.     TempODContainer newContainer = container;
  2766.     ODNewDocument(fEV, newContainer, rootPartType, editor);    
  2767.     }
  2768.     
  2769.     if( fAPPLProcess )
  2770.         this->OpenFile(newFile);
  2771.     else
  2772.         this->OpenAnotherFile(newFile, kODNULL, kODTrue, kODTrue);        // Both are true because this is a new unsaved doc
  2773.     return newFile;
  2774. }
  2775.  
  2776. //-------------------------------------------------------------------------------------
  2777. // New File(Name/Spec)
  2778. //-------------------------------------------------------------------------------------
  2779.  
  2780. ODStatic void    CreateNewUntitledFile(PlatformFile* newFile, 
  2781.                         char* fileNameSeed)
  2782. {
  2783.     Str255        fileName; // !!!! MUST BE AN ARRAY IN ORDER TO WORK (sizeof used below)
  2784.         
  2785.     if (newFile->IsStationery())
  2786.     {
  2787.         newFile->GetAsciiName((char*)fileName, sizeof(fileName)-1);
  2788.     }
  2789.     else if (fileNameSeed != kODNULL)
  2790.     {
  2791.         strncpy((char*)fileName, fileNameSeed, sizeof(fileName)-1);
  2792.     }
  2793.     else
  2794.     {
  2795.         strcpy((char*)fileName, "");
  2796.     }
  2797.     
  2798.     CToPascalString((char*)fileName);
  2799.     if ( fileName[0] > kODMaxFileNameSize )
  2800.         (void)ClipStringToBytes( fileName, kODMaxFileNameSize, smSystemScript );
  2801.     PascalToCString(fileName);
  2802.     
  2803.     newFile->SetAsciiName((char*)fileName);
  2804.     
  2805.     CreateNewFile(newFile, kODForceNewName);
  2806. }
  2807.  
  2808. void    CreateNewFile(PlatformFile* newFile, ODBoolean forceNewName)
  2809. {
  2810.     ODSLong        seed = 0;
  2811.     ODULong        err = noErr;
  2812.  
  2813.     ODSByte         prefixName[kODMaxFileNameSize+1];
  2814.     newFile->GetAsciiName(prefixName, kODMaxFileNameSize);
  2815.     prefixName[kODMaxFileNameSize] = 0;
  2816.     ODUShort    prefixLen = strlen(prefixName);
  2817.  
  2818.     ODSByte         newName[kODMaxFileNameSize+1];
  2819.     strcpy(newName,prefixName);
  2820.     
  2821.     ODFileSpec fs = newFile->GetFileSpec();
  2822.  
  2823.     while (GetVolumeWritableSpace(&fs, kODNULL) < kSpaceNeededForNewDocument)
  2824.     {
  2825.         
  2826.         THROW_IF_ERROR(FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  2827.                                 &(fs.vRefNum), &(fs.parID)));
  2828.         
  2829.         if (GetVolumeWritableSpace(&fs, &err) >= kSpaceNeededForNewDocument)
  2830.               break;
  2831.  
  2832.         THROW_IF_ERROR(err);
  2833.         THROW(kODErrSystemVolumeIsFull);
  2834.  
  2835.     // It would be nice to try other volumes as well, like:
  2836.     //   iterate through local non-removable volumes
  2837.     //     if enough space on one of those, then use it & break; break;
  2838.     //   iterate through local removable volumes
  2839.     //     if enough space on one of those, then use it & break; break;
  2840.     //   iterate through remote volumes
  2841.     //     if enough space on one of those, then use it & break; break;
  2842.     
  2843.     //  THROW(kODErrAllWritableVolumesAreFull);
  2844.  
  2845.     }
  2846.     newFile->Specify(&fs);
  2847.     newFile->UniquifyName( kODNoResourceID /*kConcatDefaultNameNoNumStrID*/, kODNULL,
  2848.             kSHLNewFilenameTemplateStrID, kODNULL, 1, kSpecifyNewNameOnly, forceNewName );
  2849.     
  2850. }    // CreateNewFile
  2851.  
  2852. void    RealShell::CreateUntitledContainer(ODDocument** documentPtr,
  2853.             ODContainer** containerPtr, PlatformFile* newFile, ODName* fileNameSeed)
  2854. {
  2855.     char* cfnSeed = kODNULL;
  2856.     if (fileNameSeed != kODNULL)
  2857.         cfnSeed = GetITextCString(fileNameSeed, kODNULL);
  2858.         
  2859.     CreateNewUntitledFile(newFile, cfnSeed);
  2860.  
  2861.     ODDeleteObject(cfnSeed);
  2862.     
  2863.     newFile->Create(kODShellSignature, kODShellSignature, 0);
  2864.  
  2865.     ODULong refNumCount;
  2866.     ODSShort* refNums;
  2867.     if (documentPtr)
  2868.     {
  2869.         GetLocalPaths(&(newFile->GetFileSpec()), kDataFork,
  2870.                           &refNumCount, &refNums);
  2871.     }
  2872.  
  2873.     (*containerPtr) = CreateFileContainer(fEV, fSession, &(newFile->GetFileSpec()));
  2874.  
  2875.     if (documentPtr)
  2876.     {
  2877.         *documentPtr = (*containerPtr)->AcquireDocument(fEV, kODDefaultDocument);    // -- TÇ: documentPtr acquires a document
  2878.     }
  2879. }
  2880.  
  2881. void    RealShell::CreateTitledContainer(ODDocument** documentPtr,
  2882.             ODContainer** containerPtr, PlatformFile* newFile, char* newName)
  2883. {
  2884.     if ( strlen(newName) > 31 )
  2885.     {
  2886.         CToPascalString( newName );
  2887.         ClipStringToBytes( (StringPtr)newName, 31, smCurrentScript );
  2888.         PascalToCString( (StringPtr)newName );
  2889.     }
  2890.     newFile->SetAsciiName(newName);
  2891.     
  2892.     CreateNewFile(newFile, kODTryCurrentName);
  2893.     
  2894.     newFile->Create(kODShellSignature, kODShellSignature, 0);
  2895.  
  2896.     ODULong refNumCount;
  2897.     ODSShort* refNums;
  2898.     if (documentPtr)
  2899.     {
  2900.         GetLocalPaths(&(newFile->GetFileSpec()), kDataFork,
  2901.                           &refNumCount, &refNums);
  2902.     }
  2903.     
  2904.     (*containerPtr) = CreateFileContainer(fEV, fSession, &(newFile->GetFileSpec()));
  2905.         
  2906.     if (documentPtr)
  2907.     {
  2908.         *documentPtr = (*containerPtr)->AcquireDocument(fEV, kODDefaultDocument);    // -- TÇ: documentPtr acquires a document
  2909.     }
  2910. }
  2911.  
  2912. //------------------------------------------------------------------------------
  2913. // Temporary File(Name/Spec)
  2914. //------------------------------------------------------------------------------
  2915.  
  2916. void    CreateTempName(short seed, Str255 name, ODBoolean isFile)
  2917. {
  2918.     // Don't modify this one!
  2919.     char* nmSeed = isFile? "ODShellTempFile" : "ODShellTempFolder";
  2920.     strcpy((char*)name, nmSeed);
  2921.  
  2922.     char theNum[10];
  2923.     NumToString(seed, (StringPtr)theNum); 
  2924.     WASSERT(theNum[0] <= 5);
  2925.     p2cstr((StringPtr)theNum);
  2926.  
  2927.     strcat((char*)name, theNum);
  2928.     c2pstr((char *)name);
  2929. }
  2930.  
  2931.  
  2932. void RealShell::CreateUniqueTmpFolderForFile(ODFileSpec* result,
  2933.         Str63 fileName)
  2934. {
  2935.     Str255        myName;
  2936.     ODSLong    myDirID;
  2937.     ODSShort    myVRef;
  2938.     GetTempFolder(&myVRef, &myDirID);
  2939.  
  2940.     OSErr err;
  2941.     short limit = kMaxUniqueNameTries;
  2942.     while ( --limit )
  2943.     {
  2944.         CreateTempName( fUniqueNameSeed++, myName, kODFalse );
  2945.         long createdDirID;
  2946.         err = DirCreate( myVRef, myDirID, myName,
  2947.                 &createdDirID );
  2948.         if ( err == noErr )
  2949.         {
  2950.             FSMakeFSSpec(myVRef, createdDirID, fileName, result);
  2951.             return;
  2952.         }
  2953.     }
  2954.     THROW( err );
  2955. }
  2956.  
  2957. void    GetTempFolder(ODSShort* VRef,ODSLong* DirID)
  2958. {
  2959.     FindFolder(0, kTemporaryFolderType, kCreateFolder,VRef,DirID);
  2960. }
  2961.  
  2962. //-------------------------------------------------------------------------------------
  2963. // CopyResources -- copy the document resources from one file to another
  2964. //-------------------------------------------------------------------------------------
  2965.  
  2966. ODStatic void    CopyResources(PlatformFile* srcFile, PlatformFile* dstFile)
  2967. {
  2968.     CUsingLibraryResources r;
  2969.     VerifyDocumentStub(&(dstFile->GetFileSpec()), kODNULL);
  2970.     // Makes sure to copy resources into the new document.
  2971.     
  2972.     ODULong sizeOfResource;
  2973.     for(ODUShort i=0; i<= 1; i++) {
  2974.         ODPtr sizeRes = srcFile->ReadResourcePtr(kSIZERsrcType, i, &sizeOfResource);
  2975.         if (sizeRes != kODNULL) {
  2976.             dstFile->WriteResourcePtr(kSIZERsrcType, i, sizeRes, sizeOfResource);
  2977.             ODDisposePtr(sizeRes);
  2978.         }
  2979.     }    
  2980. }
  2981.  
  2982. //-------------------------------------------------------------------------------------
  2983. // Open
  2984. //-------------------------------------------------------------------------------------
  2985.  
  2986. ODDocument*
  2987. RealShell::OpenFile(PlatformFile* file, ODBoolean forceOpenApp /*=false*/)
  2988. {
  2989. // if the file is a stationery seed, 
  2990. //    produce mature stationery in the Stationery folder and quit
  2991. // else create a new container if the given file is stationery
  2992. // else open the container and document and current draft and install ShellPlugIns
  2993. // note: file is not consumed and is presumed to be disposed of by the caller
  2994.  
  2995. // 'forceOpenApp' is true when an app containing a document is being launched.
  2996. // (The 'oapp' handler will set this to true.) If so we should assume that this
  2997. // is an OpenDoc document regardless of its filetype, and open it read-only.
  2998.     
  2999. //    WARN("Entering RealShell::OpenFile.");
  3000.  
  3001.     ODBoolean    isUnsavedNewDocument = kODFalse;
  3002.  
  3003.     WatchCursor();
  3004.     ODPlatformType fileType = file->GetPlatformType();
  3005.     
  3006.     // This is the stationery seed file hidden created by the launcher and
  3007.     //    hidden from the user.
  3008.     ODFileSpec fs = file->GetFileSpec();
  3009.     
  3010.     // ASSERT(the document is at the end of the resource chain)
  3011.  
  3012.     ODSShort numSeeds = Count1Resources(kDocSeedResType);
  3013.     if (numSeeds > 0)
  3014.     {
  3015.         //    Just create mature stationery and quit
  3016.  
  3017.         // Create real stationery in the stationery folder.
  3018.         FindStationeryFolder(&(fs.vRefNum), &(fs.parID));
  3019.         file->Specify(&fs);
  3020.         
  3021.         for (;numSeeds;--numSeeds)
  3022.         {
  3023.             Handle            seedEditor;
  3024.             ODContainer*    container;
  3025.             short            unusedID; 
  3026.             ResType            unusedType;
  3027.             Str255            editorName;
  3028.             
  3029.             TRY
  3030.                 seedEditor = Get1IndResource(kDocSeedResType, numSeeds);
  3031.                 TempODType editor = (ODType)ODNewPtr(GetHandleSize(seedEditor),0);//•minor leak [FIXED]
  3032.                 HLock(seedEditor);        //• unnecessary; CFM libs have no segments
  3033.                 strcpy((char*)editor, (char*)*seedEditor);
  3034.                 HUnlock(seedEditor);
  3035.  
  3036.                 // Don't allow stationery creation for viewers.
  3037.                 ODValueNameSpace*    theViewerNameSpace;
  3038.                 theViewerNameSpace = (ODValueNameSpace*)fSession
  3039.                                         ->GetNameSpaceManager(fEV)
  3040.                                         ->HasNameSpace( fEV, kODViewer );
  3041.                 ODBoolean    isAViewer;
  3042.                 TempODByteArrayStruct    ignore;
  3043.                 isAViewer = theViewerNameSpace->GetEntry(fEV, editor, ignore);
  3044.  
  3045.                 if (isAViewer)
  3046.                     GenericAlert(kSHLAlertCantMakeStationery);
  3047.                 else
  3048.                 {
  3049.                     GetResInfo(seedEditor, &unusedID, &unusedType, editorName);
  3050.     //                if (editorName[0] > 31)
  3051.     //                    ClipStringToBytes( editorName, 31, smCurrentScript );
  3052.                     PascalToCString(editorName);
  3053.                     CreateTitledContainer(kODNULL, &container, file, (char*)editorName);//•minor leak on exception [FIXED]
  3054.                     TempODContainer tempContainer = container; // ensures it's released
  3055.     
  3056.                     ODNewDocument(fEV, tempContainer, kODNULL, editor);
  3057.                     TempODDocument    newDocument = tempContainer->AcquireDocument(fEV, kODDefaultDocument);
  3058.                     TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  3059.                     ODClearIsUnsavedNewDocument(fEV, newDraft);
  3060.                     newDraft->Externalize(fEV);
  3061.                     file->SetStationery(kODTrue);
  3062.                             
  3063.                     RemoveResource(seedEditor);
  3064.                 }
  3065.             CATCH_ALL
  3066.                 // try to create doc from statinery, so throw it away, but OK to fail
  3067.                 TRY
  3068.                     file->MoveToTrash();
  3069.                 CATCH_ALL
  3070.                 ENDTRY
  3071.                 RERAISE;
  3072.             ENDTRY
  3073.         }
  3074.  
  3075.         UpdateResFile(CurResFile());        
  3076.         fDispatcher->Exit(fEV);
  3077.         return kODNULL;    // Didn't open any document
  3078.     }
  3079.     else
  3080.     {
  3081.         //    Not creating stationery
  3082.  
  3083.         PlatformFile*    newFile = kODNULL;
  3084.         ODVolatile(newFile);
  3085.         if (file->IsOpenDocDocument())
  3086.         {                              
  3087.             //    Is OpenDoc document
  3088.  
  3089.             if (file->IsStationery()) 
  3090.             {
  3091.                 //    Opening a new doc from stationery
  3092.                 //    Set up new untitled document for code below
  3093.             
  3094.             TRY
  3095.                 ODContainer*    container = kODNULL;
  3096.                 ODDocument*        document = kODNULL;
  3097.                 ODDraft*        draft = kODNULL;
  3098.                 ODAcquireCtrDocTopDraft(fEV, fSession, file, &container, &document, &draft);
  3099.                 TempODContainer    sContainer = container;
  3100.                 TempODDocument    sDocument = document;
  3101.                 TempODDraft        sDraft = draft;
  3102.     
  3103.                 newFile = new PlatformFile;
  3104.                 newFile->SpecifyFromFile(file);
  3105.                 
  3106.                 container = kODNULL; document = kODNULL;
  3107.                 
  3108.                 
  3109.                 CreateUntitledContainer(&document, &container, newFile);
  3110.                 
  3111.                 
  3112.                 TempODContainer    newContainer = container;
  3113.                 TempODDocument    newDocument = document;
  3114.                 
  3115.                 CopyResources(file, newFile);
  3116.                 newDocument->SetBaseDraftFromForeignDraft(fEV, sDraft);    
  3117.                 TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  3118.                 {
  3119.                 TempODStorageUnit su = newDraft->AcquireDraftProperties(fEV);
  3120.                 ODResetDateModByInfo(fEV, su);
  3121.                 }
  3122.                 {
  3123.                 TempODStorageUnit su = ODAcquireRootPartSUOfDraft(fEV, newDraft);
  3124.                 ODResetDateModByInfo(fEV, su);    
  3125.                 }
  3126.                 ODSetIsUnsavedNewDocument(fEV, newDraft);
  3127.                 isUnsavedNewDocument = kODTrue;
  3128.                 newDraft->Externalize(fEV);
  3129.  
  3130.                 newFile->SetPlatformType(file->GetPlatformType());
  3131.                 newFile->SetPlatformCreator(file->GetPlatformCreator());
  3132.                     
  3133.                 {
  3134.                     TempODDocumentName name(newFile->GetName());
  3135.                     newDocument->SetName(fEV, name);
  3136.                     if (!fAPPLProcess)
  3137.                         SetProcessName(name);
  3138.                 }
  3139.                             
  3140.                 file = newFile;
  3141.             CATCH_ALL
  3142.                 if (newFile)
  3143.                 {
  3144.                 TRY
  3145.                     newFile->MoveToTrash();
  3146.                 CATCH_ALL
  3147.                 ENDTRY
  3148.                 }
  3149.                 RERAISE;
  3150.             ENDTRY
  3151.             }
  3152.                         
  3153.         }
  3154.         else if( !forceOpenApp )
  3155.         {            
  3156.             //    Not an OpenDoc document, create a new OpenDoc document from it.
  3157.     
  3158.             // translate fileType into an OpenDoc kind
  3159.             TempODType theKind = fSession->GetTranslation(fEV)->
  3160.                 GetISOTypeFromPlatformType(fEV, fileType, kODPlatformFileType);
  3161.             
  3162.             // Check to see if fileType is supported by an OpenDoc Editor
  3163.             ODEditor theEditor = fSession->GetBinding(fEV)->ChooseEditorForPart( fEV, kODNULL, theKind );
  3164.             if (!theEditor)
  3165.             {
  3166.                 fDispatcher->Exit(fEV);  
  3167.                 THROW( kODErrCouldNotBindForeignDocument );
  3168.             }
  3169.             
  3170.             // create new File
  3171.             newFile    = new PlatformFile();        //• leak on exception
  3172.             newFile->SpecifyFromFile(file);
  3173.             Str255    fileName;
  3174.             Str255    newName;
  3175.             newFile->GetAsciiName( (char*)fileName, kODMaxFileNameSize );
  3176.             CToPascalString((char*)fileName);
  3177.             { CUsingLibraryResources r;
  3178.                 ReplaceIntoString(kSHLPreODDocNameStrID, fileName,
  3179.                                     kODEmptyPString, newName);
  3180.             }
  3181.             PascalToCString(newName);
  3182.             
  3183.             // Need actual object pointers because of CreateTitledContainer calling conventions
  3184.             ODDocument* document = kODNULL;
  3185.             ODContainer* container = kODNULL;
  3186.             
  3187.             CreateTitledContainer(&document, &container, newFile, (char*)newName);
  3188.             // Now immediately assign to tempobj's to be exception safe.
  3189.             TempODContainer newContainer = container;
  3190.             TempODDocument newDocument = document;
  3191.  
  3192.             HFSFlavor hfsFlavor;
  3193.             hfsFlavor.fileType = fileType;
  3194.             hfsFlavor.fileCreator = file->GetPlatformCreator();
  3195.             hfsFlavor.fdFlags = file->GetFInfoFlags();
  3196.             hfsFlavor.fileSpec = file->GetFileSpec();
  3197.  
  3198.             ((ODUByte*)(&fileType))[0] = kODPlatformKindFileChar1;
  3199.             newFile->SetPlatformType(fileType); 
  3200.             
  3201.             TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  3202.             TempODStorageUnit su = newDraft->AcquireDraftProperties(fEV);
  3203.             ODResetDateModByInfo(fEV, su);
  3204.  
  3205.             TempODStorageUnit rootPartSU = newDraft->CreateStorageUnit(fEV);
  3206.             ODSetRootPartSUOfDraft(fEV, newDraft, rootPartSU);
  3207.             
  3208.                 // create contents prop/ value for kODApplehfs
  3209.             ODSUAddPropValue(fEV, rootPartSU, kODPropContents, kODApplehfs);
  3210.             StorageUnitSetValue(rootPartSU, fEV, sizeof( hfsFlavor ), &hfsFlavor);
  3211.             rootPartSU->AddValue(fEV, theKind);
  3212.  
  3213.             //ODSetISOStrProp(fEV, rootPartSU, kODPropPreferredEditor, kODEditor, theEditor);
  3214.             
  3215.             // Preferred editor properties must be updated atomically. 
  3216.             ODSetPreferredEditorProps(rootPartSU,theEditor);
  3217.  
  3218.             ODSetIsUnsavedNewDocument(fEV, newDraft);
  3219.             newDraft->Externalize(fEV);
  3220.             file = newFile;
  3221.         }
  3222.         
  3223.         ODDocument* document = kODNULL; // this is the return value
  3224.         ODDraft*    topDraft = kODNULL;
  3225.  
  3226.         // Create document-opening helper class.
  3227.         ODOpenDocumentRef* docRef
  3228.                 = new ODOpenDocumentRef(fSession, file,
  3229.                     forceOpenApp ? kODDPReadOnly : kODDPExclusiveWrite);
  3230.  
  3231.         ODVolatile(topDraft);
  3232.         
  3233.         TRY
  3234.             // Open the document
  3235.             TRY
  3236.  
  3237.                 topDraft = docRef->Open(fEV);
  3238. //                topDraft = ODOpenFileDocument(fEV, fSession, file,
  3239. //                                forceOpenApp ?kODDPReadOnly :kODDPExclusiveWrite);
  3240.  
  3241.                 this->InstallShellPlugIns(topDraft);
  3242. //MMFillHeap(kMMBlock);
  3243.                 docRef->OpenDraft(fEV, topDraft);
  3244. //                ODOpenDraft(fEV, fSession, topDraft);
  3245.             CATCH_ALL
  3246.                 // Temporary error handling still necessary as opening code has
  3247.                 //    not been completely fixed yet. However, if we aren't in a
  3248.                 //    low-memory situation, and we don't have a fatal error, we
  3249.                 //    should be able to continue from here and let the shell
  3250.                 //    shut everything down normally.            
  3251.  
  3252.                 // By inspection, if we receive this error code, it's fatal.
  3253.                 if ( ErrorCode() == kODErrBentoInvalidProperty )    // (should be kODErrBentoErr)
  3254.                     ODShellCorruptDocGoodbye();
  3255.                 // $$$$$ - Cleanup code cannot handle out-of-memory errors yet, so this
  3256.                 //    is temporary!
  3257.                 else if (( ErrorCode() == -108)
  3258.                             || (ErrorCode() == kODErrOutOfMemory) )
  3259.                     ODShellLowTempMemoryGoodbye();
  3260.  
  3261.                 RERAISE;
  3262.  
  3263. //                else
  3264. //                    ODShellGenericGoodbye( ErrorCode() != kODErrAlreadyNotified );
  3265.             ENDTRY
  3266.             document = topDraft->GetDocument(fEV);
  3267.             // Presumably because the top draft has a refcount of 2 after
  3268.             //    ::Open
  3269.             ODReleaseObject(fEV, topDraft);
  3270.  
  3271.             fDispatcher = fSession->GetDispatcher(fEV);
  3272.             fWindowState = fSession->GetWindowState(fEV);
  3273.             fArbitrator = fSession->GetArbitrator( fEV );
  3274.         
  3275.             ODFileSpec fileFSSpec = file->GetFileSpec();
  3276.     
  3277.             LMSetSFSaveDisk(-(fileFSSpec.vRefNum));
  3278.             LMSetCurDirStore(fileFSSpec.parID);
  3279.             ODDeleteObject(newFile);
  3280.             
  3281.             if (!fAPPLProcess) {
  3282.                 ODIconFamily    icons;
  3283.                 icons = GetRootPartIconFamily(fEV, fSession);
  3284.                 SetProcessIcon(icons);
  3285.             }
  3286.         CATCH_ALL
  3287.             this->CheckFreeMemory(); // consider why this is there at all
  3288.  
  3289.             WARN("Throw occurred while opening document.");
  3290.  
  3291.             if (topDraft)
  3292.             {
  3293.                 TRY
  3294.                     ODDocument* document = topDraft->GetDocument(fEV);
  3295.                     ODSafeReleaseObject(topDraft);
  3296. //                    topDraft->Release(fEV);
  3297. //                    ODFinalReleaseObject(fEV, topDraft);
  3298.                     // This call attempts to clean up anything ODOpenDraft may
  3299.                     //    have done until now. We should fix ODOpenDraft and
  3300.                     //    anything it calls to clean up after themselves instead.
  3301.                     //    Then we can remove this call.
  3302.                     ODCloseDocument(fEV, fSession, document);
  3303.                 CATCH_ALL
  3304.                     WARN("Closing document failed, probably ODCloseDocument!");
  3305.                 ENDTRY
  3306.             }
  3307.  
  3308. //            ODFinalReleaseObject(fEV, document);
  3309.  
  3310.             // Make sure we tell the dispatcher to exit, otherwise, the process
  3311.             //    just hangs around with no windows!
  3312.             TRY
  3313.                 // Presumably a test for whether this was the first or not the
  3314.                 //    first document being opened.
  3315.                 TempODWindow activeWindow = ODAcquireActiveWindow(fEV,
  3316.                                                                      fSession);
  3317.                 if (activeWindow == kODNULL)
  3318.                     fDispatcher->Exit(fEV);
  3319.             CATCH_ALL
  3320.                 fDispatcher->Exit(fEV);
  3321.                 RERAISE;
  3322.             ENDTRY
  3323.  
  3324.             // OpenFile is not always called from an Apple event handler.
  3325.             //    This call should appear higher up in the calling chain or the
  3326.             //    error from AEProcessAppleEvent should be used instead.
  3327.             this->SetAEError(ErrorCode());
  3328.         ENDTRY
  3329.         
  3330.         delete docRef;
  3331.         
  3332.         ArrowCursor();
  3333.         
  3334.         return document;
  3335.     }
  3336. }    // RealShell::OpenFile
  3337.  
  3338. //------------------------------------------------------------------------------
  3339. // RealShell::OpenAnotherFile
  3340. //------------------------------------------------------------------------------
  3341.  
  3342. void    RealShell::OpenAnotherFile(PlatformFile* file,
  3343.                                     AEDescList* replyInfo, 
  3344.                                     ODBoolean deleteOnFailure,
  3345.                                     ODBoolean unsavedDoc)
  3346. {
  3347.     // launch another document stub to open the passed in PlatformFile
  3348.     OSErr err = noErr;
  3349.     ODFileSpec theDocument = file->GetFileSpec();
  3350.     if (WasLaunchedThenActivate(&theDocument,  kAEOpenDocuments, err))
  3351.         return;
  3352.             
  3353.     ODSLong    savedRefNum;
  3354.     BeginUsingLibraryResources(savedRefNum);
  3355.     AEDesc docDesc;
  3356.     ProcessSerialNumber psn;
  3357.     err = AECreateDesc( typeFSS, &theDocument, sizeof(theDocument),
  3358.             &docDesc );
  3359.     if ( !err )
  3360.     {
  3361.         err = VerifyAndLaunchDocumentStub(&docDesc, replyInfo, &psn,
  3362.                 kAEOpenDocuments, kODNULL, unsavedDoc);
  3363.         AEDisposeDesc( &docDesc );
  3364.     }
  3365.     EndUsingLibraryResources(savedRefNum);
  3366.     if ( err ) {
  3367.         if( deleteOnFailure )
  3368.             file->Delete();
  3369.         THROW( err );
  3370.     } else if( deleteOnFailure ) {
  3371.         // Remember PSN and spec in case launch fails; CFM will send us an error and
  3372.         // we can then delete the new file. See HandleLaunchFailedEvent...
  3373.         fLastNewDocPSN = psn;
  3374.         fLastNewDocSpec= file->GetFileSpec();
  3375.     }
  3376. }
  3377.  
  3378. //------------------------------------------------------------------------------
  3379. // OpenFileFilter
  3380. //
  3381. //    Return true (don't show this item) for invisible files and folders
  3382. //
  3383. //    Addendum: There appears to be no way to filter out invisible folders, since
  3384. //    thie function is only passed files. Oh well. Leaving code in anyway in case
  3385. //    this changes.
  3386. //------------------------------------------------------------------------------
  3387.  
  3388. static pascal Boolean OpenFileFilter(CInfoPBPtr fileInfo, void* data)
  3389. {
  3390.     if (fileInfo->hFileInfo.ioFlAttrib & ioDirMask) // FOLDER
  3391.     {
  3392.         if (fileInfo->dirInfo.ioDrUsrWds.frFlags & fInvisible)
  3393.             return true;
  3394.     }
  3395.     else // FILE
  3396.     {
  3397.         if (fileInfo->hFileInfo.ioFlFndrInfo.fdFlags & fInvisible)
  3398.             return true;
  3399.     }
  3400.  
  3401.     return false;
  3402. }
  3403.  
  3404.  
  3405. //------------------------------------------------------------------------------
  3406. // ShellDialogFilterProcYD
  3407. //
  3408. // A modal filter proc that simply calls through to the DlogUtil filter proc.
  3409. // Its purpose in life is to accept the forth argument ("data") passed by
  3410. // CustomPutFile and CustomGetFile.
  3411. //------------------------------------------------------------------------------
  3412.  
  3413. static pascal Boolean
  3414. ShellDialogFilterProcYD( DialogPtr dp, EventRecord *event, short *item, void* data )
  3415. {
  3416.     return ODDialogFilterProc( dp, event, item );
  3417. }
  3418.  
  3419.  
  3420. //------------------------------------------------------------------------------
  3421. // RealShell::OpenStdFile
  3422. //------------------------------------------------------------------------------
  3423.  
  3424. void    RealShell::OpenStdFile()
  3425. {
  3426.     // call display StdFile (with all documents) and open document in a new shell
  3427.     ArrowCursor();
  3428.     StandardFileReply sfReply;
  3429.     SFTypeList sfTypes;
  3430.     
  3431.     fWindowState->DeactivateFrontWindows(fEV);
  3432.  
  3433.     FileFilterYDUPP openFileFilterUPP = NewFileFilterYDProc(OpenFileFilter);
  3434.     ModalFilterYDUPP modalFilterUPP = NewModalFilterYDProc( ShellDialogFilterProcYD );
  3435.     ODPoint point( -1, -1);
  3436.     {
  3437.         TempODMenuBar currentMenuBar = fWindowState->AcquireCurrentMenuBar( fEV );
  3438.         ODDialogBegin( fEV, fSession, currentMenuBar, kODNULL );
  3439.         CustomGetFile( openFileFilterUPP, -1, sfTypes, &sfReply, 0, 
  3440.             point.AsQDPoint(), kODNULL, modalFilterUPP, kODNULL, kODNULL, kODNULL );
  3441.         ODDialogEnd();
  3442.     }
  3443.     DisposeRoutineDescriptor(openFileFilterUPP);
  3444.     DisposeRoutineDescriptor( modalFilterUPP );
  3445.  
  3446.     fWindowState->ActivateFrontWindows(fEV);
  3447.  
  3448.     if (sfReply.sfGood) 
  3449.     {
  3450.         TempPlatformFile file = new PlatformFile();
  3451.         file->Specify(&sfReply.sfFile);
  3452.         if( ! file->IsOpenDocDocument() )
  3453.         {
  3454.             THROW_IF_ERROR( SendFinderODOCEvent( &sfReply.sfFile ) );
  3455.  
  3456.             // Fix #1221901:
  3457.             // else (if creator≠ kODShellSignature)
  3458.             // 'appl' = launch application
  3459.             // else 'snd ' = play sound
  3460.             // else 'cdev' = open control panel
  3461.             // else use MEO,desktop database to find appropriate application to use,
  3462.             //    then launch application with document
  3463.         } else {
  3464.             // Open document in this process if I am an application process
  3465.             // with the same signature as the doc; e.g. CyberDog.
  3466.             // Otherwise launch doc into a new OD process.
  3467.             ProcessInfoRec info;
  3468.             GetCurrentProcessInfo(&info);
  3469.             if( info.processType=='APPL' && info.processSignature==file->GetPlatformCreator() )
  3470.                 this->OpenFile(file);
  3471.             else
  3472.                 this->OpenAnotherFile(file);
  3473.         }
  3474.     }
  3475. }
  3476.  
  3477. //-------------------------------------------------------------------------------------
  3478. // DoesUserCancelClose
  3479. //
  3480. //    To do: Fix flow of control
  3481. //-------------------------------------------------------------------------------------
  3482.  
  3483. ODBoolean    RealShell::DoesUserCancelClose(ODDocument* document, DescType saveOptions)
  3484. {
  3485. // asks user "Save changes before closing? Discard Changes, Cancel , Save"
  3486.     ODBoolean stillSave;
  3487.     switch(saveOptions)
  3488.     {
  3489.         case kAEAsk:
  3490.         {
  3491.             if (AEInteractWithUser(kNoTimeOut, NULL, NULL) != noErr)
  3492.                 return kODTrue;
  3493.             ArrowCursor();
  3494.             char    fileName[256];
  3495.             ODGetDocumentFileName(fEV, document, &(fileName[0]));
  3496.             CToPascalString(fileName);
  3497.  
  3498.  
  3499.             ODSShort btnClicked;
  3500.             if (ODIsTempDocument(fEV, fSession, document))
  3501.             {
  3502.                 if (ODIsUnsavedNewDocument(fEV, fSession, document))
  3503.                     btnClicked = kSHLscNo;
  3504.                 else
  3505.                     btnClicked = kSHLscOK;
  3506.             }
  3507.             else
  3508.             {
  3509.                 ODSLong        savedRefNum;
  3510.                 BeginUsingLibraryResources(savedRefNum);
  3511.                 ParamText((unsigned char const *)fileName, kODEmptyPString, 
  3512.                             kODEmptyPString, kODEmptyPString);
  3513.                 fWindowState->DeactivateFrontWindows(fEV);
  3514.                 TRY
  3515.                 {
  3516.                     DialogPtr askSaveDlg = kODNULL;
  3517.                     askSaveDlg = ODGetNewDialog( fEV, kSHLsvChanges, fSession, kODTrue );
  3518.                     THROW_IF_NULL( askSaveDlg );
  3519.                     ODUseCommandKeyStringsResource( kSHLsvChangesCmdKeyStrs );
  3520.                     ::ShowWindow( askSaveDlg );
  3521. //                    FIX_THIS_PLACE
  3522.                     ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  3523.                     ::DisposeDialog( askSaveDlg );
  3524.                 }
  3525.                 CATCH_ALL
  3526.                 {
  3527.                     btnClicked = kSHLscCancel;        // Cancel the close
  3528.                 }
  3529.                 ENDTRY
  3530.      
  3531.                 fWindowState->ActivateFrontWindows(fEV);
  3532.     
  3533.                 EndUsingLibraryResources(savedRefNum);
  3534.                 if (btnClicked == kSHLscOK)
  3535.                 {
  3536.                 TempPlatformFile file = 
  3537.                     GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3538.                 // if we try to save but file is locked, report error
  3539.                 THROW_IF_ERROR(file->LockError());
  3540.                 }
  3541.             }
  3542.             if (btnClicked == kSHLscCancel)
  3543.                 return kODTrue;
  3544.             else if (btnClicked == kSHLscNo &&
  3545.                      ODIsUnsavedNewDocument(fEV, fSession, document))
  3546.             {
  3547.                 TempPlatformFile file = 
  3548.                     GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3549.                 //    try your best to move to trash, it may fail when disk is locked
  3550.                 TRY
  3551.                     file->MoveToTrash();
  3552.                 CATCH_ALL
  3553.                 ENDTRY
  3554.             }
  3555.                 
  3556.             stillSave = (btnClicked == kSHLscOK);
  3557.         }
  3558.             break;
  3559.         case kAEYes:
  3560.             stillSave = kODTrue;
  3561.             break;
  3562.         case kAENo:
  3563.             stillSave = kODFalse;
  3564.             break;
  3565.         default:
  3566.             THROW(errAETypeError);
  3567.     }
  3568.  
  3569.     if (stillSave) 
  3570.     {
  3571.         if (this->Save(document, kODTrue, saveOptions))
  3572.             ;
  3573.         else // The user canceled the Save As dialog, which cancels the close
  3574.             return kODTrue;
  3575.     }
  3576.     return kODFalse;
  3577. }
  3578.  
  3579.  
  3580. void    RealShell::CloseWindow(ODPlatformWindow pwindow, DescType saveOptions)
  3581. {
  3582.     if (pwindow==kODNULL)
  3583.     {
  3584.         fDispatcher->Exit(fEV);
  3585.         return;
  3586.     }
  3587.     
  3588.     if (!fWindowState->IsODWindow(fEV,pwindow))
  3589.     {
  3590.         ASSERT(fWindowState->IsODWindow(fEV,pwindow), kODErrClosingNonODWindow);
  3591.         return;
  3592.     }
  3593.     
  3594.     ODWindow*  window = fWindowState->AcquireODWindow(fEV,pwindow);
  3595.     if (!window)
  3596.         return;    
  3597.  
  3598.     ODDraft* draft = window->GetDraft(fEV);
  3599.     ODDocument* document = draft->GetDocument(fEV);
  3600.     ODBoolean isOnlyTopDraftWindow =
  3601.         window->IsRootWindow(fEV) && (fWindowState->GetRootWindowCount(fEV,draft) == 1) && 
  3602.         (!(document->Exists(fEV, kODNULLID, draft, kODPosFirstAbove)));
  3603.  
  3604.     if (isOnlyTopDraftWindow &&
  3605.         ODDraftHasWriteAccess(fEV, draft) &&
  3606.         (draft->ChangedFromPrev(fEV) || ODIsUnsavedNewDocument(fEV, fSession, document)))
  3607.     {
  3608.         if (saveOptions == kAEYes)
  3609.         {
  3610.             ODSaveDocument(fEV, fSession, document);
  3611.         }
  3612.         else 
  3613.         {
  3614.             ODReleaseObject(fEV, window);    // balances AcquireODWindow above
  3615.  
  3616.             if (this->DoesUserCancelClose(document, saveOptions))
  3617.                 return;
  3618.                 
  3619.             window = fWindowState->AcquireODWindow(fEV,pwindow); // reacquire because user did not cancel close
  3620.             // NOTE: If the user SAVED the document inside the DoesUserCancelClose 
  3621.             // call above for the first time, (thereby using StdFile), and to a 
  3622.             // different volume, then DoesUserCancelClose did NOT reopen the document,
  3623.             // and pwindow is no longer a valid WindowPtr.  Therefore, the windowstate 
  3624.             // does not find it, and return kODNULL which causes the same code 
  3625.             // execution as if the return statement above was executed.
  3626.         }
  3627.     }
  3628.     
  3629.     if (window)
  3630.         if (ODReleaseCloseWindow(fEV, fSession, window)) // balances AcquireODWindow above
  3631.             fDispatcher->Exit(fEV);
  3632. }
  3633.  
  3634. //------------------------------------------------------------------------------
  3635. // RealShell::CloseDocument
  3636. //
  3637. //    Result of true means that document was closed (or close was attempted).
  3638. //    Result of false means that the process was cancelled. 
  3639. //------------------------------------------------------------------------------
  3640.  
  3641. ODBoolean RealShell::CloseDocument(ODDocument* document, DescType saveOptions)
  3642. {
  3643.     ODDraft*    draft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  3644.     ODBoolean    result = kODTrue;
  3645.     
  3646.     if (draft != kODNULL &&
  3647.         ODDraftHasWriteAccess(fEV, draft) &&
  3648.         (draft->ChangedFromPrev(fEV) || ODIsUnsavedNewDocument(fEV, fSession,
  3649.                                                                 document)))
  3650.     {
  3651.         if (this->DoesUserCancelClose(document, saveOptions))
  3652.             result = kODFalse;
  3653.     }
  3654.     if (result == kODTrue)
  3655.     {
  3656.         if (ODCloseDocument(fEV, fSession, document))
  3657.             fDispatcher->Exit(fEV);
  3658.     }
  3659.  
  3660.     return result;
  3661. }
  3662.  
  3663. //------------------------------------------------------------------------------
  3664. // RealShell::DeleteDocument
  3665. //------------------------------------------------------------------------------
  3666.  
  3667. void RealShell::DeleteDocument(ODDocument* document)
  3668. {
  3669.     // First, ask the user if they are sure they want to delete!
  3670.     if (!IsOptionKeyDown())
  3671.     {
  3672.         ArrowCursor();
  3673.     
  3674.         char    fileName[256];
  3675.         ODGetDocumentFileName(fEV, document, &(fileName[0]));
  3676.         CToPascalString(fileName);
  3677.     
  3678.         ODSLong        savedRefNum;
  3679.         BeginUsingLibraryResources(savedRefNum);
  3680.     
  3681.         ParamText(kODEmptyPString, (unsigned char const *)fileName, 
  3682.                     kODEmptyPString, kODEmptyPString);
  3683.     
  3684.         fWindowState->DeactivateFrontWindows(fEV);
  3685.         
  3686.         ODSShort btnClicked;
  3687.         TRY
  3688.         {
  3689.             DialogPtr askRevertDlg = kODNULL;
  3690.             askRevertDlg = ODGetNewDialog( fEV, kSHLDeleteDLOG, fSession, kODTrue );
  3691.             THROW_IF_NULL( askRevertDlg );
  3692.             ODUseCommandKeyStringsResource( kSHLDeleteDLOGCmdKeyStrs );
  3693.             ::ShowWindow( askRevertDlg );
  3694.             ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  3695.             ::DisposeDialog( askRevertDlg );
  3696.         }
  3697.         CATCH_ALL
  3698.         {
  3699.             btnClicked = kSHLscCancel;        // Cancel the delete
  3700.         }
  3701.         ENDTRY;
  3702.     
  3703.         fWindowState->ActivateFrontWindows(fEV);
  3704.     
  3705.         EndUsingLibraryResources(savedRefNum);
  3706.         if (!(kSHLscOK == btnClicked))
  3707.             return;
  3708.     }
  3709.     
  3710.     TempPlatformFile    
  3711.         currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));                            
  3712.  
  3713.     ODSaveDocument(fEV, fSession, document); // saving?????
  3714.     if (ODCloseDocument(fEV, fSession, document))
  3715.         fDispatcher->Exit(fEV);
  3716.         
  3717.     currentFile->MoveToTrash();
  3718. }
  3719.  
  3720. //------------------------------------------------------------------------------
  3721. // Save
  3722. //------------------------------------------------------------------------------
  3723.  
  3724. ODBoolean    RealShell::Save(ODDocument* document, ODBoolean isClosing,
  3725.                             ODDescType saveOptions)
  3726. {
  3727.     ODVolatile(isClosing);
  3728.     ODVolatile(document);
  3729.  
  3730.     if (ODIsUnsavedNewDocument(fEV, fSession, document) && saveOptions == kAEAsk)
  3731.     {
  3732.         StandardFileReply reply;
  3733.         Str255 fileName;
  3734.         ODBoolean            wasStationery;
  3735.  
  3736.         ODGetDocumentFileName(fEV, document, (char*)&(fileName[0]));
  3737.         CToPascalString((char*)fileName);
  3738.         
  3739.         Str255 msg;                
  3740.         { CUsingLibraryResources r;
  3741.             GetIndString(msg, kSHLStrsID, kSHLStrIndDSaveAs);
  3742.         }
  3743.         
  3744.         TempPlatformFile
  3745.             currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3746.         wasStationery = currentFile->IsStationery();
  3747.         
  3748.         // Need to rename file on disk briefly to avoid erroneous "Replace?" dialog
  3749.         
  3750.         // $$$$$ DOES NOT ACCOUNT FOR THE CASE WHERE THE filename+" " already exists !!!!!!
  3751.         
  3752.         FSSpec currentFSSpec = currentFile->GetFileSpec();
  3753.         if (currentFSSpec.name[0] < kODMaxFileNameSize)
  3754.             currentFSSpec.name[++currentFSSpec.name[0]] = 0x20;
  3755.         else
  3756.             --currentFSSpec.name[0];
  3757.         
  3758.         TRY
  3759.             currentFile->Rename(currentFSSpec.name);
  3760.         CATCH_ALL
  3761.             WARN("Unable to rename to avoid replace dialog. One replace dialog coming up!");
  3762.         ENDTRY
  3763.         
  3764.         // This would be cleaner, but not optimal
  3765.         // currentFile->UniquifyName(,,,,kRenameInPlace);
  3766.         
  3767.         ODDraft* draft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  3768.         ODBoolean isStationery = 
  3769.             this->AskUserWhereToPutIt(draft, fileName, msg, &reply );
  3770.  
  3771.         if (!reply.sfGood) 
  3772.         {
  3773.             TRY
  3774.                 currentFile->Rename(fileName);
  3775.             CATCH_ALL
  3776.             ENDTRY
  3777.             return kODFalse;
  3778.         }
  3779.         
  3780.         {
  3781.             // This assumes that the front window is the one being saved.
  3782.             // This might not be true for scripting, although it is right now
  3783.             // since we can only script the front window.
  3784.             TempODWindow window = fWindowState->AcquireFrontRootWindow(fEV);
  3785.             TempPlatformFile usersFile = ODGetFileIfRoot(fEV,
  3786.                                     window->GetRootFacet(fEV)->GetFrame(fEV));
  3787.             if (usersFile)
  3788.                 usersFile->SetStationery(isStationery);
  3789.             // RESET INITED BIT OF FILE. THE FINDER HAS A BUG
  3790.             //    WHERE IT WON'T UPDATE THE ICON IN THE FINDER IF ONLY THE
  3791.             //    STATIONERY BIT IS CHANGED.
  3792.             if (wasStationery != isStationery
  3793.                     && usersFile->IsEqualTo(currentFile))
  3794.                 usersFile->UnsetFinderFlag(kHasBeenInited);
  3795.         }
  3796.         
  3797.         TempPlatformFile file = new PlatformFile();
  3798.         file->Specify(&reply.sfFile);
  3799.         
  3800.         if (file->IsEqualTo(currentFile))
  3801.             ; // do nothing, we'll save down below right ontop of the current document.
  3802.         else 
  3803.         {
  3804.             if (reply.sfReplacing)
  3805.             {
  3806.                 TRY
  3807.                     file->Delete();
  3808.                 CATCH_ALL
  3809.                     THROW(kODErrCannotSaveAsOntoBusyDoc);
  3810.                 ENDTRY;
  3811.             }
  3812.             
  3813.             if (reply.sfFile.vRefNum == currentFile->GetFileSpec().vRefNum)
  3814.             {
  3815.                 currentFile->MoveRename(&(reply.sfFile), kODFalse);
  3816.             }
  3817.             else
  3818.             {
  3819.                 if (!isClosing)
  3820.                     this->ShowSaveDiffVolDialog();
  3821.                 
  3822.                 TRY
  3823.                     ODSaveDocument(fEV, fSession, document);
  3824.     
  3825.                     // Make sure copy works before closing document
  3826.                     file->CopyFrom(currentFile);
  3827.     
  3828.                     ODBoolean wasLastDocument = ODCloseDocument(fEV, fSession,
  3829.                                                                 document);
  3830.                     document = kODNULL;
  3831.     
  3832.                     // Continue if we can't delete original file
  3833.                     TRY
  3834.                         currentFile->Delete();
  3835.                     CATCH_ALL
  3836.                         WARN("Can't delete original temp file in RealShell::Save.");
  3837.                     ENDTRY
  3838.     
  3839.                     if (!isClosing) 
  3840.                     {
  3841.                         ODDraft* topDraft = ODOpenFileDocument(fEV, fSession,
  3842.                                                 file, kODDPExclusiveWrite);
  3843.                         document = topDraft->GetDocument(fEV);
  3844.                         this->InstallShellPlugIns(topDraft);
  3845.                 
  3846.                         ODOpenDraft(fEV, fSession, topDraft);
  3847.                         this->CloseSaveDiffVolDialog();
  3848.                         
  3849.                         ODReleaseObject(fEV, topDraft);
  3850.             
  3851.                         fDispatcher = fSession->GetDispatcher(fEV);
  3852.                         fWindowState = fSession->GetWindowState(fEV);
  3853.                         fArbitrator = fSession->GetArbitrator( fEV );
  3854.                     }
  3855.                     else
  3856.                     {
  3857.                         if (wasLastDocument)
  3858.                             fDispatcher->Exit(fEV);
  3859.                     }
  3860.                     
  3861.                     LMSetSFSaveDisk(-(reply.sfFile.vRefNum));
  3862.                     LMSetCurDirStore(reply.sfFile.parID);
  3863.                 CATCH_ALL
  3864.                     // Must make the doc look unsaved again because
  3865.                     //    ODSaveDocument will remove this property.
  3866.                     if (document)
  3867.                     {
  3868.                         ODDraft* tempDraft = ODGetTempDraftFromOpenDocument(fEV,
  3869.                                                         fSession, document);
  3870.                         if (tempDraft)
  3871.                             ODSetIsUnsavedNewDocument(fEV, draft);
  3872.                     }
  3873.  
  3874.                     if (!isClosing)
  3875.                         this->CloseSaveDiffVolDialog();
  3876.                     RERAISE;
  3877.                 ENDTRY
  3878.             }
  3879.         }
  3880.     }
  3881.  
  3882.     ODSetIsTempDocument(fEV, ODGetTempDraftFromOpenDocument(fEV, fSession, document), kODFalse);
  3883.     ODSaveDocument(fEV, fSession, document);
  3884.     return kODTrue;
  3885. }    // RealShell::Save
  3886.  
  3887. void RealShell::ShowSaveDiffVolDialog( )
  3888. {
  3889.     if( !fSaveDiffVolDialog ) {
  3890.         CUsingLibraryResources r;
  3891.         fSaveDiffVolDialog = ::GetNewDialog(kSHLSaveDiffVolDialogID,kODNULL,(WindowPtr)-1L);
  3892.         ::ShowWindow(fSaveDiffVolDialog);
  3893.         ::DrawDialog(fSaveDiffVolDialog);
  3894.     }
  3895. }
  3896.  
  3897. void RealShell::CloseSaveDiffVolDialog( )
  3898. {
  3899.     if( fSaveDiffVolDialog ) {
  3900.         CUsingLibraryResources r;
  3901.         ::DisposeDialog(fSaveDiffVolDialog);
  3902.         fSaveDiffVolDialog = kODNULL;
  3903.     }
  3904. }
  3905.  
  3906. //-------------------------------------------------------------------------------------
  3907. // Save A Copy
  3908. //-------------------------------------------------------------------------------------
  3909.  
  3910. pascal void DrawSmallIcon(DialogPtr theDialog, short theItem)
  3911. {
  3912.     short  itemHit;
  3913.     Handle scratchHandle;
  3914.     Rect   scratchRect;
  3915.     
  3916.     GetDialogItem(theDialog, theItem, &itemHit, &scratchHandle, &scratchRect);
  3917.  
  3918.     (void) PlotIconID (&scratchRect, atNone, ttNone,
  3919.                        theItem == kSHLSaCDocumentIconItem ? kSHLSaCDocumentIconID : kSHLSaCStationeryIconID);
  3920. }
  3921.  
  3922. pascal short SaveCopyDlgHook(short item, DialogPtr theDialog, void *saveDataPtr)
  3923. {
  3924.     short  itemHit;
  3925.     Handle scratchHandle;
  3926.     Rect   scratchRect;
  3927.     ODSShort     translateItem = 0;
  3928.     ODSShort     currentKindItem = 0;
  3929.     
  3930.     UserItemUPP drawSmallIconUPP = ((SaveCopyStruct*)saveDataPtr)->iconUPP;
  3931.     
  3932.     if ( ((WindowPeek)theDialog)->refCon == sfMainDialogRefCon )
  3933.         switch (item) {
  3934.         case sfHookFirstCall:
  3935.             GetDialogItem(theDialog, kSHLSaCDocumentIconItem, &itemHit, &scratchHandle, &scratchRect);
  3936.             SetDialogItem(theDialog, kSHLSaCDocumentIconItem, itemHit, (Handle) drawSmallIconUPP, &scratchRect);
  3937.     
  3938.             GetDialogItem(theDialog, kSHLSaCStationeryIconItem, &itemHit, &scratchHandle, &scratchRect);
  3939.             SetDialogItem(theDialog, kSHLSaCStationeryIconItem, itemHit, (Handle) drawSmallIconUPP, &scratchRect);
  3940.             
  3941.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3942.             SetControlValue( (ControlHandle) scratchHandle, !((SaveCopyStruct*)saveDataPtr)->makeStationery);
  3943.     
  3944.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3945.             SetControlValue( (ControlHandle) scratchHandle, ((SaveCopyStruct*)saveDataPtr)->makeStationery);
  3946.             
  3947.             GetDialogItem(theDialog, kSHLSaCKindPopupItem, &itemHit, &scratchHandle, &scratchRect);
  3948.             MenuHandle kindMenu = GetMenu(kSHLSaCKindPopupMenu);
  3949.             THROW_IF_NULL(kindMenu);
  3950.  
  3951.             InitKindsPopup(((SaveCopyStruct*)saveDataPtr)->kindList, 
  3952.                             ((SaveCopyStruct*)saveDataPtr)->partKind, 
  3953.                             (ControlHandle)scratchHandle, 0, 
  3954.                             ¤tKindItem, kindMenu, &translateItem,
  3955.                             ((SaveCopyStruct*)saveDataPtr)->session);
  3956.             break;
  3957.     
  3958.         case kSHLSaCDocumentRadioBtn :
  3959.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3960.             SetControlValue( (ControlHandle) scratchHandle, 1);
  3961.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3962.             SetControlValue( (ControlHandle) scratchHandle, 0);
  3963.             
  3964.             break;
  3965.             
  3966.         case kSHLSaCStationeryRadioBtn :
  3967.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3968.             SetControlValue( (ControlHandle) scratchHandle, 0);
  3969.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3970.             SetControlValue( (ControlHandle) scratchHandle, 1);
  3971.     
  3972.             break;
  3973.             
  3974.         case sfHookLastCall :
  3975.             /* check value of radio buttons and save accordingly */
  3976.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3977.             ((SaveCopyStruct*)saveDataPtr)->makeStationery = GetControlValue( (ControlHandle) scratchHandle);
  3978.             ((SaveCopyStruct*)saveDataPtr)->changeKind = kODNULL;
  3979.             GetDialogItem(theDialog, kSHLSaCKindPopupItem, &itemHit, &scratchHandle, &scratchRect);
  3980.             ODSShort kindItem = (ODSShort) GetControlValue((ControlHandle)scratchHandle);
  3981.             if (kindItem != currentKindItem)
  3982.             {
  3983.                 ODType newKind = GetThisKindFromList(kindItem,
  3984.                                     ((SaveCopyStruct*)saveDataPtr)->kindList);
  3985.                 ((SaveCopyStruct*)saveDataPtr)->changeKind = newKind;
  3986.             }
  3987.         
  3988.             break;
  3989.         }
  3990.                                                                                                                                 
  3991.     return (item);
  3992. }
  3993.  
  3994. ODBoolean RealShell::AskUserWhereToPutIt( ODDraft* whichDraft, Str255 defaultName,
  3995.         Str255 msg, StandardFileReply* reply )
  3996. {
  3997.     Point              pt;
  3998.     SetPt(&pt, 0, 0);
  3999.  
  4000.     ODBoolean    makeStationery;
  4001.  
  4002.     ODSLong        savedRefNum;
  4003.         // Setup fSaveCopyData fields for custom put file
  4004.     fSaveCopyData = new SaveCopyStruct;
  4005.  
  4006.     fSaveCopyData->session = this->GetSession();
  4007.     TempODPart rootPart = ODAcquireRootPartOfDraft(fEV, whichDraft);
  4008.     
  4009.     ODContainer* container = whichDraft->GetDocument(fEV)->GetContainer(fEV);
  4010.     TempPlatformFile file = GetPlatformFileFromContainer(fEV, container);
  4011.     fSaveCopyData->makeStationery = file->IsStationery();
  4012. //    fSaveCopyData->makeStationery = kODFalse; // always default to saving a document
  4013.     
  4014.  
  4015.     fSaveCopyData->partKind = ODGetKind(fEV, rootPart );
  4016.     fSaveCopyData->kindList = 
  4017.         fSession->GetStorageSystem(fEV)->CreateTypeList(fEV, kODNULL);
  4018.  
  4019.         // get StorageUnit kinds
  4020.     ContentValueTypes(rootPart->GetStorageUnit(fEV), fSaveCopyData->kindList);
  4021.  
  4022.         // get all kinds supported by this editor
  4023.     ODNameSpaceManager* nsm = fSaveCopyData->session->GetNameSpaceManager(fEV);
  4024.     ODEditor editorID = GetCurrentEditorForPart(rootPart);
  4025.     GetAllKindsForEditor(nsm, fSaveCopyData->kindList, editorID);
  4026.     ODDisposePtr(editorID);
  4027.     
  4028.     BeginUsingLibraryResources(savedRefNum);
  4029.     fSaveCopyData->iconUPP = NewUserItemProc(DrawSmallIcon);
  4030.     DlgHookYDUPP saveACopyUPP = NewDlgHookYDProc(SaveCopyDlgHook);
  4031.     ModalFilterYDUPP modalFilterUPP = NewModalFilterYDProc( ShellDialogFilterProcYD );
  4032.  
  4033.     fWindowState->DeactivateFrontWindows(fEV);
  4034.     
  4035.     {
  4036.         TempODMenuBar currentMenuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  4037.         ODDialogBegin(fEV, fSession, currentMenuBar, kODNULL);
  4038.         CustomPutFile(msg, defaultName, reply,
  4039.                       kSHLSaveCopyDlgID, pt, saveACopyUPP, modalFilterUPP, 
  4040.                       kODNULL , kODNULL, fSaveCopyData);
  4041.         ODDialogEnd();
  4042.     }
  4043.  
  4044.     fWindowState->ActivateFrontWindows(fEV);
  4045.  
  4046.     DisposeRoutineDescriptor(saveACopyUPP);    
  4047.     DisposeRoutineDescriptor(fSaveCopyData->iconUPP);
  4048.     DisposeRoutineDescriptor( modalFilterUPP );
  4049.      EndUsingLibraryResources(savedRefNum);
  4050.  
  4051.     makeStationery = fSaveCopyData->makeStationery;
  4052.     
  4053.     ODDisposePtr( fSaveCopyData->partKind );
  4054.     ODDeleteObject( fSaveCopyData->kindList );
  4055.     ODDeleteObject( fSaveCopyData );
  4056.     
  4057.      return makeStationery;
  4058. }
  4059.  
  4060. void RealShell::SaveACopy(ODDraft* draft)        
  4061. {
  4062. // save a copy of the topmost draft into a new container
  4063.     StandardFileReply reply;
  4064.     
  4065.     Str255 msg;
  4066.     
  4067.     ODDocument* document = draft->GetDocument(fEV);
  4068.     
  4069.     Str255 fileName;
  4070.     ODGetDocumentFileName(fEV, document, (char*)&(fileName[0]));
  4071.     CToPascalString((char*)fileName);
  4072.     
  4073.     Str255 defaultName;
  4074.     
  4075.     // HI$ #1247070: should we append " Draft <n>" if the user happens to be saving
  4076.     // a copy of a draft?
  4077.     
  4078.     { CUsingLibraryResources r;
  4079.         GetIndString(msg, kSHLStrsID, kSHLStrIndDSaveACopy);
  4080.         ReplaceIntoString(kSHLCopyDefaultStrID, fileName, kODEmptyPString, defaultName);
  4081.     }
  4082.     if (defaultName[0] > kODMaxFileNameSize)
  4083.         ClipStringToBytes( defaultName, kODMaxFileNameSize, smCurrentScript );
  4084.     
  4085.     ODBoolean isStationery = 
  4086.         this->AskUserWhereToPutIt(draft, defaultName, msg, &reply );
  4087.     if (!reply.sfGood) 
  4088.         return;
  4089.  
  4090.     // This is the real file we'll end up with
  4091.     TempPlatformFile file = new PlatformFile();
  4092.     file->Specify(&reply.sfFile);
  4093.     // But we will write to a file in the temp folder first and then block
  4094.     //    copy the results to the real file. The real file doesn't appear at all
  4095.     //    if anything goes wrong.
  4096.     TempPlatformFile tempFile = new PlatformFile();
  4097.     FSSpec    tempFileSpec;
  4098.     // Embedded string is OK because it's not a user visible file.
  4099.     CreateUniqueTmpFolderForFile(&tempFileSpec, "\pODSaveACopyTemp");
  4100.     tempFile->Specify(&tempFileSpec);
  4101.     
  4102.     TempPlatformFile
  4103.         currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  4104.  
  4105.     if (reply.sfReplacing)
  4106.     {
  4107.         ODBoolean isEqual = file->IsEqualTo(currentFile);
  4108.         
  4109.         if (isEqual != kODFalse)
  4110.         {
  4111.             THROW(kODErrCannotSaveACopyOntoCurrentDoc);
  4112.         }
  4113.         
  4114.         TRY
  4115.             file->Delete();
  4116.         CATCH_ALL
  4117.             THROW(kODErrCannotSaveACopyOntoBusyDoc);
  4118.         ENDTRY;
  4119.     }
  4120.     
  4121.     ODSaveACopyOfDraft(fEV, fSession, draft, tempFile);
  4122.  
  4123.     tempFile->SetStationery(isStationery);
  4124.     // copy the resource over to the new copy
  4125.     CopyResources(currentFile, tempFile);
  4126.  
  4127.     // OK, finally copy the results to the real file or just move and rename it
  4128.     //    if it's on the same volume.
  4129.     TRY
  4130.         if (reply.sfFile.vRefNum == tempFileSpec.vRefNum)
  4131.             tempFile->MoveRename(&(reply.sfFile), kODFalse);
  4132.         else
  4133.             file->CopyFrom(tempFile);
  4134.     CATCH_ALL
  4135.         file->Delete();
  4136.         RERAISE;
  4137.     ENDTRY
  4138. }
  4139.  
  4140.  
  4141. void
  4142. RealShell::CloseAllDocs( DescType /* saveOptions */ ) // will be handled by
  4143.                                                         // quit handler
  4144. {
  4145.     // CyberDog wants to intercept the quit apple event, so send ourselves one.
  4146.  
  4147.     ProcessSerialNumber    psn = {0, kCurrentProcess};
  4148.     OSErr                error = noErr;
  4149.     AEAddressDesc        address = {typeNull, NULL};
  4150.     AppleEvent            message = {typeNull, NULL};
  4151.     AppleEvent            reply = {typeNull, NULL};
  4152.  
  4153.     ODVolatile(error);
  4154.  
  4155.     TRY
  4156.         THROW_IF_ERROR(AECreateDesc(typeProcessSerialNumber, (Ptr)&psn, sizeof(psn),
  4157.                                     &address));
  4158.         THROW_IF_ERROR(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication,
  4159.                         &address, kAutoGenerateReturnID, kAnyTransactionID,
  4160.                         &message));
  4161.         THROW_IF_ERROR(AESend(&message, &reply,
  4162.                                 kAENoReply + kAECanInteract,
  4163.                                 kAENormalPriority, kAEDefaultTimeout,
  4164.                                 (AEIdleUPP)kODNULL, (AEFilterUPP)kODNULL));
  4165.     CATCH_ALL
  4166.         error = ErrorCode();
  4167.     ENDTRY
  4168.  
  4169.     AEDisposeDesc(&address);
  4170.       AEDisposeDesc(&message);
  4171.       AEDisposeDesc(&reply);
  4172.  
  4173.     THROW_IF_ERROR(error);
  4174.  
  4175. #if 0
  4176.     for( TempODWindowIterator wi(fEV,fSession->GetWindowState(fEV)); wi; ++wi ) {
  4177.         ODDocument *document = ODGetDraftOfWindow(fEV,wi)->GetDocument(fEV);
  4178.         if( ! this->CloseDocument(document, saveOptions) )
  4179.             return; /* user canceled */
  4180.     }
  4181.     // CloseDocument method will tell dispatcher to exit when last doc closes.
  4182. #endif /* 0 */
  4183. }
  4184.  
  4185.  
  4186. //-------------------------------------------------------------------------------------
  4187. // Revert
  4188. //-------------------------------------------------------------------------------------
  4189.  
  4190.  
  4191. void    RealShell::Revert(ODDocument* document)
  4192. {
  4193.     if (this->DoesUserOKRevert(document)) 
  4194.     {
  4195.         ODRevertDocument(fEV, fSession, document);
  4196.     }
  4197. }
  4198.  
  4199. ODBoolean    RealShell::DoesUserOKRevert(ODDocument* document)
  4200. {
  4201. // asks user "Revert to the last saved version?"
  4202.  
  4203.     ArrowCursor();
  4204.  
  4205.     char    fileName[256];
  4206.     ODGetDocumentFileName(fEV, document, &(fileName[0]));
  4207.     CToPascalString(fileName);
  4208.  
  4209.     ODSLong        savedRefNum;
  4210.     BeginUsingLibraryResources(savedRefNum);
  4211.  
  4212.     ParamText(kODEmptyPString, (unsigned char const *)fileName, 
  4213.                 kODEmptyPString, kODEmptyPString);
  4214.  
  4215.     fWindowState->DeactivateFrontWindows(fEV);
  4216.     
  4217.     ODSShort btnClicked;
  4218.     TRY
  4219.     {
  4220.         DialogPtr askRevertDlg = kODNULL;
  4221.         askRevertDlg = ODGetNewDialog( fEV, kSHLsvRevert, fSession, kODTrue );
  4222.         THROW_IF_NULL( askRevertDlg );
  4223.         ODUseCommandKeyStringsResource( kSHLsvRevertCmdKeyStrs );
  4224.         ::ShowWindow( askRevertDlg );
  4225.         ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  4226.         ::DisposeDialog( askRevertDlg );
  4227.     }
  4228.     CATCH_ALL
  4229.     {
  4230.         btnClicked = kSHLscCancel;        // Cancel the revert
  4231.     }
  4232.     ENDTRY;
  4233.  
  4234.     fWindowState->ActivateFrontWindows(fEV);
  4235.  
  4236.     EndUsingLibraryResources(savedRefNum);;
  4237.     return kSHLscOK == btnClicked;
  4238. }
  4239.  
  4240.  
  4241. //-------------------------------------------------------------------------------------
  4242. // Drafts
  4243. //-------------------------------------------------------------------------------------
  4244. #ifdef _USE_DIALOGS_LIB_
  4245. #ifdef __cplusplus
  4246. extern "C" {
  4247. #endif
  4248. typedef ODError (*DraftWindowEntry)( Environment* ev, ODSession* session,
  4249.         ODWindowState* winState, ODDocument* document );
  4250. #ifdef __cplusplus
  4251. }
  4252. #endif
  4253.  
  4254. OSErr LoadODSharedLibrary( Str63 libName, Str255 entryName,
  4255.         CFragConnectionID* connID, void** entryPoint );
  4256. void UnloadODSharedLibrary( CFragConnectionID* connID );
  4257.  
  4258. #endif
  4259. void    RealShell::Drafts(ODDocument* document)
  4260. {
  4261. #ifdef _USE_DIALOGS_LIB_
  4262.     DraftWindowEntry dwi = kODNULL;
  4263.     CFragConnectionID connID ;
  4264.     THROW_IF_ERROR( LoadODSharedLibrary( "\pDialogsLib",
  4265.             "\pDraftWindowEntry", &connID, (void**)&dwi ) );
  4266.     THROW_IF_ERROR( (*dwi)( fEV, fSession, fWindowState, document ) );
  4267.     UnloadODSharedLibrary( &connID );
  4268.     return;
  4269. #else
  4270.     ODDraft* topDraft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  4271.     if (topDraft)
  4272.         topDraft->Acquire(fEV);
  4273.     else
  4274.         topDraft = document->AcquireDraft(fEV,kODDPReadOnly,0,kODNULL,kODPosTop,kODFalse);
  4275.     
  4276.     DraftWindow* d = new DraftWindow;
  4277.     DraftWinAction     dWinAction = kDraftWinNone;
  4278.     ODDraft*    curDraft = kODNULL;
  4279.     d->InitDraftWindow(fEV, topDraft);
  4280.  
  4281.     fWindowState->DeactivateFrontWindows(fEV);
  4282.     ArrowCursor();
  4283.     do {
  4284.         dWinAction = d->Drafts(fEV, curDraft, dWinAction, ODDraftHasWriteAccess(fEV, topDraft));
  4285.         switch (dWinAction) {
  4286.             case kDraftWinCreate:
  4287.                 WASSERT(ODDraftHasWriteAccess(fEV, topDraft));
  4288.                 fWindowState->ActivateFrontWindows(fEV);
  4289.                 d->DraftSaved(fEV, topDraft);
  4290.                 ODSaveDocument(fEV, fSession, document);
  4291.                 ODCloseDraft(fEV, fSession, topDraft);
  4292. #ifdef ODDebug
  4293.                 ODULong topDraftRefCount = topDraft->GetRefCount(fEV);
  4294.                 WASSERT(topDraftRefCount == 2);
  4295. #endif
  4296.                 topDraft->Release(fEV); // to balance the CreateDraft when the document was opened
  4297.                 topDraft = document->CreateDraft(fEV, topDraft, kODTrue);
  4298.                     // This CreateDraft call is doing two things with refcounts.
  4299.                     // First, it is releasing topDraft which balances the Acquire at the top of
  4300.                     // this function.
  4301.                     // Second, it is creating a new temp draft, which puts us in the same
  4302.                     // state as we were before the above topDraft->Release, except
  4303.                     // for the need to Reacquire the topDraft as was done at the top of this 
  4304.                     // function which we do in the next statement.
  4305.                 topDraft->Acquire(fEV);
  4306.                 
  4307.                 ODTempDraftCreated(fEV, fSession, document, topDraft);
  4308.                 curDraft = topDraft;
  4309.  
  4310.                 {
  4311.                 TempODStorageUnit su = topDraft->AcquireDraftProperties(fEV);
  4312.                 ODResetDateModByInfo(fEV, su);    
  4313.                 }
  4314.                 
  4315.                 d->InitDraftWindow(fEV, topDraft);
  4316.                 ODOpenDraft(fEV, fSession, topDraft);
  4317.                 ODSaveDocument(fEV, fSession, document);
  4318.                 fWindowState->DeactivateFrontWindows(fEV);
  4319.                 
  4320.                 break;
  4321.             case kDraftWinDelete:
  4322.                 ODDraft* selDraft = d->GetSelectedDraft();
  4323.  
  4324.                 ODCloseDraft(fEV, fSession, selDraft);
  4325.                 ODReleaseObject( fEV, selDraft );    // -- TÇ: was acquired in draftswindow
  4326.  
  4327.                 d->DeleteSelectedDraft(fEV, fSession); 
  4328.                 break;
  4329.         }
  4330.     } while (dWinAction == kDraftWinDelete);
  4331.  
  4332.     fWindowState->ActivateFrontWindows(fEV);
  4333.     
  4334.     if (dWinAction == kDraftWinOpen)
  4335.     {
  4336.         // open selected Drafts as additional root windows within this process
  4337.         // if a particular draft already has a window, bring it to front, don't create a new one
  4338.         ODDraft* selDraft = d->GetSelectedDraft();
  4339.         WASSERT(selDraft);
  4340.         
  4341.         ODOpenDraft(fEV, fSession, selDraft);
  4342.     }
  4343.     ODDeleteObject(d);
  4344.     ODReleaseObject( fEV, topDraft );    // balances Acquire & AcquireDraft at beginning.
  4345.  
  4346.     if ( dWinAction == kDraftWinLowMemAbort )
  4347.         THROW( kODErrOutOfMemory );
  4348. #endif
  4349. }
  4350.  
  4351. //-------------------------------------------------------------------------------------
  4352. // Info
  4353. //-------------------------------------------------------------------------------------
  4354.  
  4355.  
  4356. void    RealShell::DocumentInfo(ODDocument* document)
  4357. {
  4358.     ODUnused(document);
  4359.     
  4360.     ODDocumentInfo(fEV, fSession);
  4361. }
  4362.  
  4363. /*
  4364. // Default implementation for active parts which do nothing.  Keep this code -TÇ.
  4365. void    RealShell::PartInfo()
  4366. {
  4367.     ArrowCursor();
  4368.     ODTypeToken selectionFocus = fSession->Tokenize(fEV, kODSelectionFocus);
  4369.     TempODFrame activeFrame = fSession->GetArbitrator(fEV)->AcquireFocusOwner(fEV, selectionFocus);
  4370.     ODFrameFacetIterator* facets = activeFrame->CreateFacetIterator(fEV);
  4371.     fSession->GetInfo(fEV)->ShowPartFrameInfo(fEV, facets->First(fEV),
  4372.         this->HasWriteAccess());
  4373.     ODDeleteObject(facets);
  4374. }
  4375. */
  4376.  
  4377. //-------------------------------------------------------------------------------------
  4378. // Error Handling
  4379. //-------------------------------------------------------------------------------------
  4380.  
  4381. void    RealShell::ExceptionAlert(ODError exceptionCode, const char message[])
  4382. {
  4383.     Str255 errStr;
  4384.  
  4385.     gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  4386.     if ( gODBentoFatalErrorHasOccurred )
  4387.         ODBentoFatalError(/*allowSuppress*/ kODFalse);
  4388.  
  4389.     // Errors not to display:
  4390.     if( exceptionCode == kODNoError || exceptionCode == kODErrAlreadyNotified
  4391.                                     || exceptionCode == userCanceledErr )
  4392.         return;
  4393.  
  4394.     // If interaction is allowed, notify user until process is activated:
  4395.     if( AEInteractWithUser(kNoTimeOut,kODNULL,kODNULL) != noErr )
  4396.         return;
  4397.     
  4398.     TRY{
  4399.     
  4400.         CUsingLibraryResources r;
  4401.  
  4402.         ODBoolean lowMem = ! this->CheckFreeMemory();
  4403.     
  4404.         TRY{
  4405.             if (fWindowState)
  4406.                 fWindowState->DeactivateFrontWindows(fEV);
  4407.         }CATCH_ALL{
  4408.             WARN("Error %d deactivating front windows",ErrorCode());
  4409.             // don't reraise
  4410.         }ENDTRY
  4411.         
  4412.         LookupErrString(exceptionCode, kODErrUserID, errStr);
  4413.         if ( fFailedPlugInName[0] != 0 )
  4414.         {
  4415.             ReplaceIntoString( kSHLPlugInErrorStrID, fFailedPlugInName, errStr, errStr);
  4416.             fFailedPlugInName[0] = 0;
  4417.         }
  4418.     
  4419.     #if ODDebug
  4420.         ParamText(errStr, "\pOption-click OK for more…", kODEmptyPString, kODEmptyPString);
  4421.             // NOTE: This hard coded string is ok because it is for debugging only. -TC
  4422.     #else
  4423.         ParamText(errStr, kODEmptyPString, kODEmptyPString, kODEmptyPString);
  4424.     #endif
  4425.     
  4426.         // Do not use a filter-proc if low on memory since it calls back to OpenDoc!
  4427.         ModalFilterUPP filter = lowMem ?kODNULL :GetODButtonKeyFilterProc();
  4428.     
  4429.     
  4430.         // Shazam! Show the alert:
  4431.         ShowAlert(fEV, kSHLphGenError, filter, fSession);
  4432.     
  4433.         TRY{
  4434.             if (IsOptionKeyDown()) 
  4435.             {
  4436.                 Str255    debugStrString;
  4437.                 debugStrString[0] = 0;
  4438.                 
  4439.                 GetIndString(debugStrString, kSHLStrsID, kSHLStrIndDException);
  4440.                 
  4441.                 Str255    tempString;
  4442.         
  4443.                 NumToString(exceptionCode, tempString);
  4444.                 if (debugStrString[0] + tempString[0] <= 255)
  4445.                     ConcatPascalStrings(debugStrString, tempString);
  4446.         
  4447.                 LookupErrString(exceptionCode, kODErrSupportID, errStr);
  4448.                 
  4449.                 char msg[256];
  4450.                 if( message ) {
  4451.                     strncpy(msg,message,255);
  4452.                     msg[255] = 0;
  4453.                     c2pstr(msg);
  4454.                 } else
  4455.                     msg[0] = 0;
  4456.                 
  4457.                 ParamText(errStr, debugStrString, (StringPtr)msg, kODEmptyPString);
  4458.                 ShowAlert(fEV, kSHLphGenError, filter, fSession);
  4459.             }
  4460.         }CATCH_ALL{
  4461.             WARN("Error %d handling opt key down",ErrorCode());
  4462.             // don't reraise
  4463.         }ENDTRY
  4464.         
  4465.     #ifdef SHLTestErrorDialogUsage
  4466.         SHLDebugStr("\pPostErrorDialog HeapInfo…");
  4467.         HeapInfo();
  4468.     #endif
  4469.             
  4470.         TRY{
  4471.             if (fWindowState)
  4472.                 fWindowState->ActivateFrontWindows(fEV);
  4473.         }CATCH_ALL{
  4474.             WARN("Error %d re-activating front windows",ErrorCode());
  4475.             // don't reraise
  4476.         }ENDTRY
  4477.     
  4478.         ResetAlertStage();
  4479.         
  4480.     }CATCH_ALL{
  4481.         SysBeep(3);
  4482.         WARN("Error %d thrown by exception alert",ErrorCode());
  4483.         // Eat exception, don't reraise
  4484.     }ENDTRY
  4485.  
  4486.     gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  4487.     if ( gODBentoFatalErrorHasOccurred )
  4488.         ODBentoFatalError(/*allowSuppress*/ kODFalse);
  4489. }
  4490.  
  4491. //----------------------------------------------------------------------------------------
  4492. // SearchErrTable: Private function
  4493. //----------------------------------------------------------------------------------------
  4494.  
  4495. ODBoolean RealShell::SearchErrTable(ODError value,
  4496.                               ODResNumber resourceID,
  4497.                               Str255 str)
  4498. {
  4499.     ErrRecordHandle table;
  4500.  
  4501.     str[0] = 0;
  4502.     ODSLong        savedRefNum;
  4503.     BeginUsingLibraryResources(savedRefNum);
  4504.     table = (ErrRecordHandle)GetResource('errs', resourceID);
  4505.     DetachResource((Handle)table);
  4506.     EndUsingLibraryResources(savedRefNum);
  4507.     
  4508.     if (table)
  4509.     {
  4510.         short lenTab;
  4511.         ODResNumber strID = 0;
  4512.         SignedByte savedState = HGetState((Handle)table);
  4513.         HLock((Handle)table);
  4514.         
  4515.         ErrRecordPointer pEntry = *table;
  4516.  
  4517.         lenTab = (short)(GetHandleSize((Handle)table) / sizeof(ErrRecord));
  4518.         for (short i = 1; i <= lenTab; ++i, ++pEntry)
  4519.         {
  4520.             if (pEntry->lowErr == 0)
  4521.                 strID = (ODResNumber)(pEntry->index);    // WARNING: assigning an ODULong to a short
  4522.             else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr))
  4523.             {
  4524.                 if (pEntry->index > 0)
  4525.                 {
  4526.                     ODSLong        savedRefNum;
  4527.                     BeginUsingLibraryResources(savedRefNum);
  4528.                     GetIndString(str, strID, (ODResNumber)(pEntry->index)); // WARNING: passing in an ODULong as a short
  4529.                     EndUsingLibraryResources(savedRefNum);;
  4530.                 }
  4531.                 return kODTrue;
  4532.             }
  4533.         }
  4534.         HSetState((Handle)table, savedState);
  4535.     }
  4536.     return kODFalse;
  4537. } // SearchErrTable 
  4538.  
  4539. //----------------------------------------------------------------------------------------
  4540. // LookupErrString: 
  4541. //----------------------------------------------------------------------------------------
  4542.  
  4543. ODBoolean RealShell::LookupErrString(ODError value,
  4544.                                ODResNumber resourceID,
  4545.                                Str255 str)
  4546. {
  4547.     if (SearchErrTable(value, 0/*errAppTable*/ + resourceID, str))
  4548.         return kODTrue;
  4549.     else
  4550.         return SearchErrTable(value, resourceID, str);
  4551. } // LookupErrString 
  4552.  
  4553. //----------------------------------------------------------------------------------------
  4554. // CreateDefaultIText: 
  4555. //
  4556. // <eeh> this might be more useful in IText.cpp or whatever it's called.
  4557. //----------------------------------------------------------------------------------------
  4558.  
  4559. static ODIText* CreateDefaultIText(StringPtr text)
  4560. {
  4561.     ODScriptCode script = FontToScript( GetSysFont() );;
  4562.     ODLangCode lang = GetScriptVariable(script, smScriptLang);
  4563.     return CreateITextPString( script, lang, text);
  4564. }
  4565.  
  4566. /*********************************************************************************
  4567. SendFinderODOCEvent
  4568. Temporary function that should be merged with Jens's CreateFinderRevealEvent in
  4569. WinPopM.cpp (UI subsystem).  Or perhaps we needn't bother, since this is just
  4570. a workaround anyway.
  4571. *********************************************************************************/
  4572.  
  4573. static OSErr SendFinderODOCEvent( const FSSpec *fileToOpen )
  4574. {
  4575.     const DescType kFinderSignature    = 'MACS';
  4576.  
  4577.     OSErr err;
  4578.     OSType finderSignature = kFinderSignature;
  4579.     AliasHandle alias = NULL;
  4580.     AEDesc target = NULL_DESCRIPTOR_DEFINITION;
  4581.     AEDescList list = NULL_DESCRIPTOR_DEFINITION;
  4582.  
  4583.     AppleEvent openEvent = NULL_DESCRIPTOR_DEFINITION;
  4584.     
  4585.     err= AECreateDesc(typeApplSignature,&finderSignature,sizeof(OSType), &target);
  4586.     if( err ) goto exit;
  4587.     err= AECreateAppleEvent( kCoreEventClass, kAEOpenDocuments, &target,
  4588.             kAutoGenerateReturnID, kAnyTransactionID, &openEvent );
  4589.     if( err ) goto exit;
  4590. //    AEDisposeDesc(&target);
  4591.     err= NewAliasMinimal( fileToOpen, &alias );
  4592.     if( err ) goto exit;
  4593.  
  4594.     err= AECreateList(NULL,0,false, &list);
  4595.     if( err ) goto exit;
  4596.     err= AEPutPtr(&list,1,typeAlias,*alias,GetHandleSize((Handle)alias));
  4597.     if( err ) goto exit;
  4598.     
  4599.     err= AEPutParamDesc(&openEvent, keyDirectObject, &list);
  4600.     if( err ) goto exit;
  4601.  
  4602.     err = AESend( &openEvent, kODNULL,
  4603.             kAENoReply|kAEAlwaysInteract|kAECanSwitchLayer,
  4604.             kAENormalPriority, kNoTimeOut, kODNULL, kODNULL );
  4605.  
  4606.     if (err == connectionInvalid)
  4607.         FinderNotRunning();
  4608.  
  4609. exit:
  4610.     AEDisposeDesc(&target);
  4611.     AEDisposeDesc(&list);
  4612.     if( alias ) DisposeHandle((Handle)alias);
  4613. //    if( err )
  4614.         AEDisposeDesc(&openEvent);
  4615.     
  4616.     return err;
  4617. }
  4618.  
  4619. //------------------------------------------------------------------------------
  4620. // FinderNotRunning
  4621. //------------------------------------------------------------------------------
  4622.  
  4623. void FinderNotRunning()
  4624. {
  4625.     StopAlert(kODAlertShellFinderNotRunning, (ModalFilterUPP)NULL);
  4626. }
  4627.  
  4628. //------------------------------------------------------------------------------
  4629. // ReportErrorGeneric
  4630. //------------------------------------------------------------------------------
  4631.  
  4632. void ReportErrorGeneric(StringPtr errorString)
  4633. {
  4634.     ReportErrorSimple(errorString);
  4635. }
  4636.  
  4637. //------------------------------------------------------------------------------
  4638. // GenericAlert
  4639. //------------------------------------------------------------------------------
  4640.  
  4641. void GenericAlert(short alertResID)
  4642. {
  4643.     TRY{
  4644.         CUsingLibraryResources r;
  4645.         InitCursor();
  4646.         ::Alert( alertResID, kODNULL );
  4647.     }CATCH_ALL{
  4648.         WARN("Couldn't show alert! Exception thrown.");
  4649.     }ENDTRY
  4650. }
  4651.